Index: group/autogroup.php
=========================================================
--- group/autogroup.php	(revision 1.10)
+++ group/autogroup.php	Sat Jul 25 13:01:17 WST 2009
@@ -17,6 +17,7 @@
 }
 
 $courseid = required_param('courseid', PARAM_INT);
+$PAGE->set_url('/group/autogroup.php', array('courseid' => $courseid));
 
 if (!$course = $DB->get_record('course', array('id'=>$courseid))) {
     print_error('invalidcourseid');
Index: group/autogroup_form.php
=========================================================
--- group/autogroup_form.php	(revision 1.5)
+++ group/autogroup_form.php	Sat Jul 25 13:31:26 WST 2009
@@ -45,8 +45,7 @@
         $mform->setAdvanced('allocateby');
 
         $mform->addElement('text', 'namingscheme', get_string('namingscheme', 'group'));
-        $mform->setHelpButton('namingscheme', array(false, get_string('namingschemehelp', 'group'),
-                false, true, false, get_string('namingschemehelp', 'group')));
+        $mform->setHelpButton('namingscheme', array('namingscheme', get_string('namingschemehelp', 'group'), 'group'));
         $mform->addRule('namingscheme', get_string('required'), 'required', null, 'client');
         $mform->setType('namingscheme', PARAM_MULTILANG);
         // there must not be duplicate group names in course
Index: help.php
=========================================================
--- help.php	(revision 1.56)
+++ help.php	Thu Jul 23 13:48:46 WST 2009
@@ -19,6 +19,7 @@
 $module = optional_param('module', 'moodle', PARAM_ALPHAEXT);
 $forcelang = optional_param('forcelang', '', PARAM_SAFEDIR);
 $skiplocal = optional_param('skiplocal', 0, PARAM_INT);     // shall _local help files be skipped?
+$fortooltip = optional_param('fortooltip', 0, PARAM_INT);
 
 $PAGE->set_course($COURSE);
 
@@ -62,8 +63,14 @@
 
 // Finish buffer
 $output = ob_get_contents();
+
 ob_end_clean();
 
+if ($fortooltip) {
+    echo shorten_text($output, 400, false, '<span class="readmore">' . get_string('clickhelpiconformoreinfo') . '</span>');
+    die();
+}
+
 // Determine title
 $title = get_string('help'); // Default is just 'Help'
 $matches = array();
Index: lang/en_utf8/moodle.php
=========================================================
--- lang/en_utf8/moodle.php	(revision 1.246)
+++ lang/en_utf8/moodle.php	Fri Jul 24 11:22:04 WST 2009
@@ -242,6 +242,7 @@
 $string['clamunknownerror'] = 'There was an unknown error with clam.';
 $string['cleaningtempdata'] = 'Cleaning temp data';
 $string['clear'] = 'Clear';
+$string['clickhelpiconformoreinfo'] = '... continues ... Click on the help icon to read the full article';
 $string['clickhere'] = 'Click here ...';
 $string['clicktochange'] = 'Click to change';
 $string['clicktohideshow'] = 'Click to expand or collapse';
Index: lib/ajax/ajaxlib.php
=========================================================
--- lib/ajax/ajaxlib.php	(revision 1.76)
+++ lib/ajax/ajaxlib.php	Fri Jul 24 11:22:58 WST 2009
@@ -32,7 +32,7 @@
  * @param page_requirements_manager $requires The page_requirements_manager to initialise.
  */
 function setup_core_javascript(page_requirements_manager $requires) {
-    global $CFG;
+    global $CFG, $OUTPUT;
 
     // JavaScript should always work with $CFG->httpswwwroot rather than $CFG->wwwroot.
     // Otherwise, in some situations, users will get warnings about insecure content
@@ -41,6 +41,7 @@
     $config = array(
         'wwwroot' => $CFG->httpswwwroot, // Yes, really. See above.
         'sesskey' => sesskey(),
+        'loadingicon' => $OUTPUT->old_icon_url('i/loading_small')
     );
     if (debugging('', DEBUG_DEVELOPER)) {
         $config['developerdebug'] = true;
@@ -56,6 +57,12 @@
     // Note that, as a short-cut, the code 
     // $js = "document.body.className += ' jsenabled';\n";
     // is hard-coded in {@link page_requirements_manager::get_top_of_body_code)
+    $requires->yui_lib('container');
+    $requires->yui_lib('connection');
+    $requires->string_for_js('confirmation', 'moodle');
+    $requires->string_for_js('cancel', 'moodle');
+    $requires->string_for_js('yes', 'moodle');
+    $requires->js_function_call('init_help_icons'); 
 }
 
 
@@ -364,8 +371,9 @@
      * @return required_event_handler The event_handler object
      */
     public function event_handler($id, $event, $function, $arguments=array()) {
-        $requirement = new required_event_handler($id, $event, $function, $arguments);
+        $requirement = new required_event_handler($this, $id, $event, $function, $arguments);
         $this->requiredjscode[] = $requirement;
+        $this->linkedrequirements[] = new required_yui_lib($this, 'event');
         return $requirement;
     }
 
@@ -1109,7 +1117,6 @@
      * @param array  $arguments An optional array of argument parameters to pass to the function
      */
     public function __construct(page_requirements_manager $manager, $id, $event, $function, $args=array()) {
-        $manager->requires->yui_lib('event');
         parent::__construct($manager);
         $this->id = $id;
         $this->event = $event;
@@ -1118,7 +1125,7 @@
     }
 
     public function get_js_code() {
-        $output = "YAHOO.util.Event.addListener($this->id, '$this->event', $this->function";
+        $output = "YAHOO.util.Event.addListener('$this->id', '$this->event', $this->function";
         if (!empty($this->args)) {
             $output .= ', ' . json_encode($this->args);
         }
Index: lib/deprecatedlib.php
=========================================================
--- lib/deprecatedlib.php	(revision 1.126)
+++ lib/deprecatedlib.php	Sat Jul 25 15:24:06 WST 2009
@@ -2379,3 +2379,595 @@
         return true;
     }
 }
+
+/**
+ * Creates and displays (or returns) a link to a popup window
+ *
+ * @deprecated since Moodle 2.0
+ *
+ * @param string $url Web link. Either relative to $CFG->wwwroot, or a full URL.
+ * @param string $name Name to be assigned to the popup window (this is used by
+ *   client-side scripts to "talk" to the popup window)
+ * @param string $linkname Text to be displayed as web link
+ * @param int $height Height to assign to popup window
+ * @param int $width Height to assign to popup window
+ * @param string $title Text to be displayed as popup page title
+ * @param string $options List of additional options for popup window
+ * @param bool $return If true, return as a string, otherwise print
+ * @param string $id id added to the element
+ * @param string $class class added to the element
+ * @return string html code to display a link to a popup window.
+ */
+function link_to_popup_window ($url, $name=null, $linkname=null,
+                               $height=400, $width=500, $title=null,
+                               $options=null, $return=false) {
+    global $OUTPUT;
+
+    // debugging('link_to_popup_window() has been deprecated. Please change your code to use $OUTPUT->link_to_popup().');
+
+    if ($options == 'none') {
+        $options = null;
+    }
+
+    if (empty($linkname)) {
+        throw new coding_exception('A link must have a descriptive text value! See $OUTPUT->link_to_popup() for usage.');
+    }
+
+    // Create a html_link object
+    $link = new html_link();
+    $link->text = $linkname;
+    $link->url = $url;
+    $link->title = $title;
+
+    // Parse the $options string
+    $popupparams = array();
+    if (!empty($options)) { 
+        $optionsarray = explode(',', $options);
+        foreach ($optionsarray as $option) {
+            if (strstr($option, '=')) {
+                $parts = explode('=', $option);
+                if ($parts[1] == '0') {
+                    $popupparams[$parts[0]] = false;
+                } else {
+                    $popupparams[$parts[0]] = $parts[1];
+                }
+            } else {
+                $popupparams[$option] = true;
+            }
+        }
+    }
+
+    $popupaction = new popup_action('click', $url, $name, $popupparams);
+    $link->add_action_object($popupaction);
+
+    // Call the output method
+    $output = $OUTPUT->link_to_popup($link);
+
+    if ($return) {
+        return $output;
+    } else {
+        echo $output; 
+    }
+}
+
+/**
+ * Creates and displays (or returns) a buttons to a popup window.
+ *
+ * @deprecated since Moodle 2.0
+ *
+ * @param string $url Web link. Either relative to $CFG->wwwroot, or a full URL.
+ * @param string $name Name to be assigned to the popup window (this is used by
+ *   client-side scripts to "talk" to the popup window)
+ * @param string $linkname Text to be displayed as web link
+ * @param int $height Height to assign to popup window
+ * @param int $width Height to assign to popup window
+ * @param string $title Text to be displayed as popup page title
+ * @param string $options List of additional options for popup window
+ * @param bool $return If true, return as a string, otherwise print
+ * @param string $id id added to the element
+ * @param string $class class added to the element
+ * @return string html code to display a link to a popup window.
+ */
+function button_to_popup_window ($url, $name=null, $linkname=null,
+                                 $height=400, $width=500, $title=null, $options=null, $return=false,
+                                 $id=null, $class=null) {
+    global $OUTPUT;
+
+    // debugging('link_to_popup_window() has been deprecated. Please change your code to use $OUTPUT->link_to_popup().');
+
+    if ($options == 'none') {
+        $options = null;
+    }
+
+    if (empty($linkname)) {
+        throw new coding_exception('A link must have a descriptive text value! See $OUTPUT->link_to_popup() for usage.');
+    }
+
+    // Create a html_button object
+    $button = new html_button();
+    $button->value = $linkname;
+    $button->url = $url;
+    $button->id = $id;
+    $button->add_class($class);
+    $button->method = 'post';
+    $button->title = $title;
+
+    // Parse the $options string
+    $popupparams = array();
+    if (!empty($options)) { 
+        $optionsarray = explode(',', $options);
+        foreach ($optionsarray as $option) {
+            if (strstr($option, '=')) {
+                $parts = explode('=', $option);
+                if ($parts[1] == '0') {
+                    $popupparams[$parts[0]] = false;
+                } else {
+                    $popupparams[$parts[0]] = $parts[1];
+                }
+            } else {
+                $popupparams[$option] = true;
+            }
+        }
+    }
+
+    if (!empty($height)) {
+        $popupparams['height'] = $height;
+    }
+    if (!empty($width)) {
+        $popupparams['width'] = $width;
+    }
+
+    $popupaction = new popup_action('click', $url, $name, $popupparams);
+    $button->add_action_object($popupaction);
+    $output = $OUTPUT->button($button);
+
+    if ($return) {
+        return $output;
+    } else {
+        echo $output; 
+    }
+}
+
+/**
+ * Print a self contained form with a single submit button.
+ *
+ * @deprecated since Moodle 2.0
+ *
+ * @param string $link used as the action attribute on the form, so the URL that will be hit if the button is clicked.
+ * @param array $options these become hidden form fields, so these options get passed to the script at $link.
+ * @param string $label the caption that appears on the button.
+ * @param string $method HTTP method used on the request of the button is clicked. 'get' or 'post'.
+ * @param string $notusedanymore no longer used.
+ * @param boolean $return if false, output the form directly, otherwise return the HTML as a string.
+ * @param string $tooltip a tooltip to add to the button as a title attribute.
+ * @param boolean $disabled if true, the button will be disabled.
+ * @param string $jsconfirmmessage if not empty then display a confirm dialogue with this string as the question.
+ * @param string $formid The id attribute to use for the form
+ * @return string|void Depending on the $return paramter.
+ */
+function print_single_button($link, $options, $label='OK', $method='get', $notusedanymore='',
+        $return=false, $tooltip='', $disabled = false, $jsconfirmmessage='', $formid = '') {
+    global $OUTPUT;
+
+    // debugging('print_single_button() has been deprecated. Please change your code to use $OUTPUT->button().');
+
+    // Cast $options to array
+    $options = (array) $options;
+    $button = new html_button();
+    $button->url = new moodle_url($link, $options);
+    $button->label = $label;
+    $button->disabled = $disabled;
+    $button->title = $tooltip;
+    $button->method = $method;
+
+    if ($jsconfirmmessage) {
+        $confirmaction = new component_action('click', 'confirmdialog', array($jsconfirmmessage));
+        $button->add_action_object($confirmaction);
+    }
+
+    $output = $OUTPUT->button($button, $formid);
+
+    if ($return) {
+        return $output;
+    } else {
+        echo $output;
+    }
+}
+
+/**
+ * Print a spacer image with the option of including a line break.
+ *
+ * @deprecated since Moodle 2.0
+ *
+ * @global object
+ * @param int $height The height in pixels to make the spacer
+ * @param int $width The width in pixels to make the spacer
+ * @param boolean $br If set to true a BR is written after the spacer
+ */
+function print_spacer($height=1, $width=1, $br=true, $return=false) {
+    global $CFG, $OUTPUT;
+
+    // debugging('print_spacer() has been deprecated. Please change your code to use $OUTPUT->spacer().');
+
+    $spacer = new html_spacer();
+    $spacer->height = $height;
+    $spacer->width = $width;
+
+    $output = $OUTPUT->spacer($spacer);
+
+    $output .= '<img class="spacer" height="'. $height .'" width="'. $width .'" src="'. $CFG->wwwroot .'/pix/spacer.gif" alt="" />';
+
+    if ($br) {
+        $output .= '<br />';
+    }
+
+    if ($return) {
+        return $output;
+    } else {
+        echo $output;
+    }
+}
+
+/**
+ * Given the path to a picture file in a course, or a URL,
+ * this function includes the picture in the page.
+ *
+ * @deprecated since Moodle 2.0
+ */
+function print_file_picture($path, $courseid=0, $height='', $width='', $link='', $return=false) {
+    throw new coding_exception('print_file_picture() has been deprecated since Moodle 2.0. Please use $OUTPUT->action_icon() instead.');
+}
+
+/**
+ * Print the specified user's avatar.
+ *
+ * @deprecated since Moodle 2.0
+ *
+ * @global object
+ * @global object
+ * @param mixed $user Should be a $user object with at least fields id, picture, imagealt, firstname, lastname
+ *      If any of these are missing, or if a userid is passed, the the database is queried. Avoid this
+ *      if at all possible, particularly for reports. It is very bad for performance.
+ * @param int $courseid The course id. Used when constructing the link to the user's profile.
+ * @param boolean $picture The picture to print. By default (or if NULL is passed) $user->picture is used.
+ * @param int $size Size in pixels. Special values are (true/1 = 100px) and (false/0 = 35px) for backward compatibility
+ * @param boolean $return If false print picture to current page, otherwise return the output as string
+ * @param boolean $link enclose printed image in a link the user's profile (default true).
+ * @param string $target link target attribute. Makes the profile open in a popup window.
+ * @param boolean $alttext add non-blank alt-text to the image. (Default true, set to false for purely
+ *      decorative images, or where the username will be printed anyway.)
+ * @return string|void String or nothing, depending on $return.
+ */
+function print_user_picture($user, $courseid, $picture=NULL, $size=0, $return=false, $link=true, $target='', $alttext=true) {
+    global $CFG, $DB, $OUTPUT;
+
+    // debugging('print_user_picture() has been deprecated. Please change your code to use $OUTPUT->user_picture($user, $link, $popup).');
+
+    $userpic = new user_picture();
+    $userpic->user = $user;
+    $userpic->courseid = $courseid;
+    $userpic->size = $size;
+    $userpic->link = $link;
+    $userpic->alttext = $alttext;
+
+    if (!empty($picture)) {
+        $userpic->image = new html_image();
+        $userpic->image->src = $picture;
+    }
+
+    if (!empty($target)) {
+        $popupaction = new popup_action('click', new moodle_url($target));
+        $userpic->add_action_object($popupaction);
+    }
+
+    $output = $OUTPUT->user_picture($userpic);
+
+    if ($return) {
+        return $output;
+    } else {
+        echo $output;
+    }
+}
+
+/**
+ * Print a png image.
+ *
+ * @deprecated since Moodle 2.0: no replacement
+ *
+ */
+function print_png() {
+    throw new coding_exception('print_png() has been deprecated since Moodle 2.0. Please use $OUTPUT->image() instead.');
+}
+
+
+/**
+ * Prints a basic textarea field.
+ *
+ * @deprecated since Moodle 2.0
+ *
+ * When using this function, you should
+ *
+ * @global object
+ * @param bool $usehtmleditor Enables the use of the htmleditor for this field.
+ * @param int $rows Number of rows to display  (minimum of 10 when $height is non-null)
+ * @param int $cols Number of columns to display (minimum of 65 when $width is non-null)
+ * @param null $width (Deprecated) Width of the element; if a value is passed, the minimum value for $cols will be 65. Value is otherwise ignored.
+ * @param null $height (Deprecated) Height of the element; if a value is passe, the minimum value for $rows will be 10. Value is otherwise ignored.
+ * @param string $name Name to use for the textarea element.
+ * @param string $value Initial content to display in the textarea.
+ * @param int $obsolete deprecated
+ * @param bool $return If false, will output string. If true, will return string value.
+ * @param string $id CSS ID to add to the textarea element.
+ * @return string|void depending on the value of $return
+ */
+function print_textarea($usehtmleditor, $rows, $cols, $width, $height, $name, $value='', $obsolete=0, $return=false, $id='') {
+    /// $width and height are legacy fields and no longer used as pixels like they used to be.
+    /// However, you can set them to zero to override the mincols and minrows values below.
+
+    // debugging('print_textarea() has been deprecated. Please change your code to use $OUTPUT->textarea().');
+
+    global $CFG;
+
+    $mincols = 65;
+    $minrows = 10;
+    $str = '';
+
+    if ($id === '') {
+        $id = 'edit-'.$name;
+    }
+
+    if ($usehtmleditor) {
+        if ($height && ($rows < $minrows)) {
+            $rows = $minrows;
+        }
+        if ($width && ($cols < $mincols)) {
+            $cols = $mincols;
+        }
+    }
+
+    if ($usehtmleditor) {
+        editors_head_setup();
+        $editor = get_preferred_texteditor(FORMAT_HTML);
+        $editor->use_editor($id, array('legacy'=>true));
+    } else {
+        $editorclass = '';
+    }
+
+    $str .= "\n".'<textarea class="form-textarea" id="'. $id .'" name="'. $name .'" rows="'. $rows .'" cols="'. $cols .'">'."\n";
+    if ($usehtmleditor) {
+        $str .= htmlspecialchars($value); // needed for editing of cleaned text!
+    } else {
+        $str .= s($value);
+    }
+    $str .= '</textarea>'."\n";
+
+    if ($return) {
+        return $str;
+    }
+    echo $str;
+}
+
+
+/**
+ * Print a help button.
+ *
+ * @deprecated since Moodle 2.0
+ *
+ * @param string $page  The keyword that defines a help page
+ * @param string $title The title of links, rollover tips, alt tags etc
+ *           'Help with' (or the language equivalent) will be prefixed and '...' will be stripped.
+ * @param string $module Which module is the page defined in
+ * @param mixed $image Use a help image for the link?  (true/false/"both")
+ * @param boolean $linktext If true, display the title next to the help icon.
+ * @param string $text If defined then this text is used in the page, and
+ *           the $page variable is ignored. DEPRECATED!
+ * @param boolean $return If true then the output is returned as a string, if false it is printed to the current page.
+ * @param string $imagetext The full text for the helpbutton icon. If empty use default help.gif
+ * @return string|void Depending on value of $return
+ */
+function helpbutton($page, $title, $module='moodle', $image=true, $linktext=false, $text='', $return=false, $imagetext='') {
+    // debugging('helpbutton() has been deprecated. Please change your code to use $OUTPUT->help_icon().');
+
+    global $OUTPUT;
+
+    if (!empty($text)) {
+        throw new coding_exception('The $text parameter has been deprecated. Please update your code and use $OUTPUT->help_icon() instead. <br />' .
+            "You will also need to copy the following text into a proper html help file if not already done so: <p>$text</p>");
+    }
+
+    if (!empty($imagetext)) {
+        throw new coding_exception('The $imagetext parameter has been deprecated. Please update your code and use $OUTPUT->help_icon() instead.');
+    }
+
+    $helpicon = new help_icon();
+    $helpicon->page = $page;
+    $helpicon->module = $module;
+    $helpicon->text = $title;
+    $helpicon->linktext = $linktext;
+    $helpicon->image = new html_image();
+    $helpicon->image->src = $OUTPUT->old_icon_url('help');
+
+    $output = $OUTPUT->help_icon($helpicon);
+
+    if ($return) {
+        return $output;
+    } else {
+        echo $output;
+    }
+
+}
+
+/**
+ * Returns an image of an up or down arrow, used for column sorting. To avoid unnecessary DB accesses, please
+ * provide this function with the language strings for sortasc and sortdesc.
+ *
+ * @deprecated since Moodle 2.0
+ *
+ * TODO migrate to outputlib
+ * If no sort string is associated with the direction, an arrow with no alt text will be printed/returned.
+ *
+ * @global object
+ * @param string $direction 'up' or 'down'
+ * @param string $strsort The language string used for the alt attribute of this image
+ * @param bool $return Whether to print directly or return the html string
+ * @return string|void depending on $return
+ *
+ */
+function print_arrow($direction='up', $strsort=null, $return=false) {
+    // debugging('print_arrow() has been deprecated. Please change your code to use $OUTPUT->arrow().');
+
+    global $OUTPUT;
+
+    if (!in_array($direction, array('up', 'down', 'right', 'left', 'move'))) {
+        return null;
+    }
+
+    $return = null;
+
+    switch ($direction) {
+        case 'up':
+            $sortdir = 'asc';
+            break;
+        case 'down':
+            $sortdir = 'desc';
+            break;
+        case 'move':
+            $sortdir = 'asc';
+            break;
+        default:
+            $sortdir = null;
+            break;
+    }
+
+    // Prepare language string
+    $strsort = '';
+    if (empty($strsort) && !empty($sortdir)) {
+        $strsort  = get_string('sort' . $sortdir, 'grades');
+    }
+
+    $return = ' <img src="'.$OUTPUT->old_icon_url('t/' . $direction) . '" alt="'.$strsort.'" /> ';
+
+    if ($return) {
+        return $return;
+    } else {
+        echo $return;
+    }
+}
+
+/**
+ * Returns a string containing a link to the user documentation.
+ * Also contains an icon by default. Shown to teachers and admin only.
+ *
+ * @deprecated since Moodle 2.0
+ *
+ * @global object
+ * @param string $path The page link after doc root and language, no leading slash.
+ * @param string $text The text to be displayed for the link
+ * @param string $iconpath The path to the icon to be displayed
+ * @return string Either the link or an empty string
+ */
+function doc_link($path='', $text='', $iconpath='') {
+    global $CFG, $OUTPUT;
+
+    // debugging('doc_link() has been deprecated. Please change your code to use $OUTPUT->action_icon().');
+
+    if (empty($CFG->docroot)) {
+        return '';
+    }
+
+    $icon = new action_icon();
+    $icon->linktext = $text;
+
+    if (!empty($iconpath)) {
+        $icon->src = $iconpath;
+        $icon->title = $text;
+        $icon->add_class('iconhelp');
+    } else {
+        $icon->src = $CFG->httpswwwroot . '/pix/docs.gif';
+    }
+
+    $icon->url = new moodle_url(get_docs_url($path));
+
+    if (!empty($CFG->doctonewwindow)) {
+        $icon->onclick = array('window.open', array($url));
+    }
+
+    return $OUTPUT->action_icon($icon);
+}
+
+/**
+ * Prints a single paging bar to provide access to other pages  (usually in a search)
+ *
+ * @deprecated since Moodle 2.0
+ *
+ * @param int $totalcount Thetotal number of entries available to be paged through
+ * @param int $page The page you are currently viewing
+ * @param int $perpage The number of entries that should be shown per page
+ * @param mixed $baseurl If this  is a string then it is the url which will be appended with $pagevar, an equals sign and the page number.
+ *                          If this is a moodle_url object then the pagevar param will be replaced by the page no, for each page.
+ * @param string $pagevar This is the variable name that you use for the page number in your code (ie. 'tablepage', 'blogpage', etc)
+ * @param bool $nocurr do not display the current page as a link
+ * @param bool $return whether to return an output string or echo now
+ * @return bool|string depending on $result
+ */
+function print_paging_bar($totalcount, $page, $perpage, $baseurl, $pagevar='page',$nocurr=false, $return=false) {
+    global $OUTPUT;
+
+    // debugging('print_paging_bar() has been deprecated. Please change your code to use $OUTPUT->paging_bar($pagingbar).');
+
+    $pagingbar = new html_paging_bar();
+    $pagingbar->totalcount = $totalcount;
+    $pagingbar->page = $page;
+    $pagingbar->perpage = $perpage;
+    $pagingbar->baseurl = $baseurl;
+    $pagingbar->pagevar = $pagevar;
+    $pagingbar->nocurr = $nocurr;
+    $output = $OUTPUT->paging_bar($pagingbar);
+
+    if ($return) {
+        return $output;
+    }
+
+    echo $output;
+    return true;
+}
+
+/**
+ * Print a message along with "Yes" and "No" links for the user to continue.
+ *
+ * @deprecated since Moodle 2.0
+ *
+ * @global object
+ * @param string $message The text to display
+ * @param string $linkyes The link to take the user to if they choose "Yes"
+ * @param string $linkno The link to take the user to if they choose "No"
+ * @param string $optionyes The yes option to show on the notice
+ * @param string $optionsno The no option to show
+ * @param string $methodyes Form action method to use if yes [post, get]
+ * @param string $methodno Form action method to use if no [post, get]
+ * @return void Output is echo'd
+ */
+function notice_yesno ($message, $linkyes, $linkno, $optionsyes=NULL, $optionsno=NULL, $methodyes='post', $methodno='post') {
+
+    // debugging('notice_yesno() has been deprecated. Please change your code to use $OUTPUT->confirm($message, $buttoncontinue, $buttoncancel).');
+
+    global $OUTPUT;
+    
+    $buttoncontinue = new html_button();
+    $buttoncontinue->url = new moodle_url($linkyes, $optionsyes);
+    $buttoncontinue->method = $methodyes;
+    $buttoncancel = new html_button();
+    $buttoncancel->url = new moodle_url($linkno, $optionsno);
+    $buttoncancel->method = $methodno;
+    
+    echo $OUTPUT->confirm($message, $buttoncontinue, $buttoncancel);
+}
+
+/**
+ * Prints a scale menu (as part of an existing form) including help button
+ * @deprecated since Moodle 2.0
+ */
+function print_scale_menu() {
+    throw new coding_exception('print_scale_menu() has been deprecated since the Jurassic period. Get with the times!.');
+}
+
Index: lib/javascript-static.js
=========================================================
--- lib/javascript-static.js	(revision 1.77)
+++ lib/javascript-static.js	Fri Jul 24 22:01:46 WST 2009
@@ -560,7 +560,7 @@
             date_selector_calendar.currentowner.release_calendar();
         }
     }
-} 
+}
 
 date_selector_calendar.prototype.claim_calendar = function() {
     date_selector_calendar.cancel_any_timeout();
@@ -733,12 +733,15 @@
     return (arrReturnElements)
 }
 
-function openpopup(url, name, options, fullscreen) {
-    var fullurl = url;
-    if (!url.match(/https?:\/\//)) {
-        fullurl = moodle_cfg.wwwroot + url;
+function openpopup(event, args) {
+
+    YAHOO.util.Event.preventDefault(event);
+
+    var fullurl = args.url;
+    if (!args.url.match(/https?:\/\//)) {
+        fullurl = moodle_cfg.wwwroot + args.url;
     }
-    var windowobj = window.open(fullurl,name,options);
+    var windowobj = window.open(fullurl,args.name,args.options);
     if (!windowobj) {
         return true;
     }
@@ -812,7 +815,7 @@
         }
 
         // Make the request.
-        YAHOO.util.Connect.asyncRequest('GET', url, callback); 
+        YAHOO.util.Connect.asyncRequest('GET', url, callback);
     }
 }
 
@@ -886,7 +889,7 @@
 collapsible_region.prototype.userpref = null;
 
 /**
- * The key divs that make up this 
+ * The key divs that make up this
  * @property div, innerdiv, captiondiv
  * @type HTMLDivElement
  */
@@ -895,7 +898,7 @@
 collapsible_region.prototype.captiondiv = null;
 
 /**
- * The key divs that make up this 
+ * The key divs that make up this
  * @property icon
  * @type HTMLImageElement
  */
@@ -1102,3 +1105,113 @@
     }
     return list.join('&');
 }
+/**
+ * Finds all help icons on the page and initiates YUI tooltips for
+ * each of them, which load a truncated version of the help's content
+ * on-the-fly asynchronously
+ */
+function init_help_icons() {
+    // var logger = new YAHOO.widget.LogReader(document.body, {draggable: true});
+
+    var iconspans = YAHOO.util.Dom.getElementsByClassName('helplink', 'span');
+
+    var tooltip = new YAHOO.widget.Tooltip('help_icon_tooltip', {
+        context: iconspans,
+        showdelay: 100,
+        hidedelay: 150,
+        autodismissdelay: 50000,
+        underlay: 'none'
+    });
+
+    tooltip.contextTriggerEvent.subscribe(
+        function(type, args) {
+            // Fetch help page contents asynchronously
+            // Load spinner icon while content is loading
+            var spinner = document.createElement('img');
+            spinner.src = moodle_cfg.loadingicon;
+
+            this.cfg.setProperty('text', spinner);
+
+            var context = args[0];
+            context.title = '';
+
+            var link = context.getElementsByTagName('a')[0];
+            link.title = '';
+            YAHOO.util.Dom.getElementsByClassName('iconhelp', 'img', link)[0].title = '';
+            var thistooltip = this;
+            var ajaxurl = link.href + '&fortooltip=1';
+
+
+            var callback = {
+                success: function(o) {
+                    thistooltip.cfg.setProperty('text', o.responseText);
+                },
+                failure: function(o) {
+                    var debuginfo = o.statusText;
+                    if (moodle_cfg.developerdebug) {
+                        o.statusText += ' (' + ajaxurl + ')';
+                    }
+                    thistooltip.cfg.setProperty('text', debuginfo);
+                }
+            };
+
+            var conn = YAHOO.util.Connect.asyncRequest("get", ajaxurl, callback);
+        }
+    );
+}
+
+/**
+ * Prints a confirmation dialog in the style of DOM.confirm().
+ * @param object event A DOM event
+ * @param string message The message to show in the dialog
+ * @param string url The URL to forward to if YES is clicked. Disabled if fn is given
+ * @param function fn A JS function to run if YES is clicked.
+ */
+function confirmdialog(event, message) {
+
+    YAHOO.util.Event.preventDefault(event);
+    
+    var simpledialog = new YAHOO.widget.SimpleDialog('confirmdialog',
+        { width: '300px',
+          fixedcenter: true,
+          modal: true,
+          visible: false,
+          draggable: false
+        }
+    );
+    
+    simpledialog.setHeader(mstr.moodle.confirmation);
+    simpledialog.setBody(message);
+    simpledialog.cfg.setProperty('icon', YAHOO.widget.SimpleDialog.ICON_WARN);
+    
+    var handlecancel = function() {
+        this.hide();
+    };
+
+    var handleyes = function() {
+        this.hide();
+        var target = event.target;
+        
+        if (target.tagName == 'A') {
+            window.location = target.href;
+        } else if (target.tagName == 'INPUT') {
+            var parentelement = target.parentNode;
+            while (parentelement.tagName != 'FORM' && parentelement.tagName != 'BODY') {
+                parentelement = parentelement.parentNode;
+            }
+            if (parentelement.tagName == 'FORM') { 
+                parentelement.submit();
+            }
+        } else if(moodle_cfg.developerdebug) {
+            alert("Element of type " + target.tagName + " is not supported by the confirmdialog function. Use A or INPUT");
+        }
+    };
+    
+    var buttons = [ { text: mstr.moodle.cancel, handler: handlecancel, isDefault: true },
+                    { text: mstr.moodle.yes, handler: handleyes } ];
+    
+    simpledialog.cfg.queueProperty('buttons', buttons);
+    
+    simpledialog.render(document.body);
+    simpledialog.show();
+}
Index: lib/outputlib.php
=========================================================
--- lib/outputlib.php	(revision 1.46)
+++ lib/outputlib.php	Sat Jul 25 15:13:13 WST 2009
@@ -15,6 +15,13 @@
 // You should have received a copy of the GNU General Public License
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
+/**
+ * This constant is used for html attributes which need to have an empty
+ * value and still be output by the renderers (e.g. alt="");
+ *
+ * @constant @EMPTY@
+ */
+define('HTML_ATTR_EMPTY', '@EMPTY@');
 
 /**
  * Functions for generating the HTML that Moodle should output.
@@ -27,7 +34,6 @@
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
-
 /**
  * A renderer factory is just responsible for creating an appropriate renderer
  * for any given part of Moodle.
@@ -1306,7 +1312,9 @@
      */
     protected function output_attribute($name, $value) {
         $value = trim($value);
-        if ($value || is_numeric($value)) { // We want 0 to be output.
+        if ($value == HTML_ATTR_EMPTY) {
+            return ' ' . $name . '=""';
+        } else if ($value || is_numeric($value)) { // We want 0 to be output.
             return ' ' . $name . '="' . $value . '"';
         }
     }
@@ -2189,6 +2197,7 @@
 
         $this->page->set_state(moodle_page::STATE_DONE);
 
+
         return $output . $footer;
     }
 
@@ -2324,12 +2333,332 @@
         return $output;
     }
 
-    public function link_to_popup_window() {
+    /**
+     * Given a html_textarea object, outputs an <a> tag that uses the object's attributes.
+     *
+     * @param mixed $link A html_link object or a string URL (text param required in second case)
+     * @param string $text A descriptive text for the link. If $link is a html_link, this is not required.
+     * @return string HTML fragment
+     */
+    public function textarea($textarea) {
+
+    }
+
+    /**
+     * Given a html_link object, outputs an <a> tag that uses the object's attributes.
+     *
+     * @param mixed $link A html_link object or a string URL (text param required in second case)
+     * @param string $text A descriptive text for the link. If $link is a html_link, this is not required.
+     * @return string HTML fragment
+     */
+    public function link($link, $text=null) {
+        $attributes = array('href' => $link);
+
+        if (is_a($link, 'html_link')) {
+            $link->prepare();
+            $attributes['href'] = prepare_url($link->url);
+            $text = $link->text;
+
+            $attributes['class'] = $link->get_classes_string();
+            $attributes['title'] = $link->title;
+            $attributes['id'] = $link->id;
+
+        } else if (empty($text)) {
+            throw new coding_exception('$OUTPUT->link() must have a string as second parameter if the first param ($link) is a string');
+        }
+
+        return $this->output_tag('a', $attributes, $text);
+    }
+   
+   /**
+    * Print a message along with button choices for Continue/Cancel. Labels default to Yes(Continue)/No(Cancel)
+    * @param string $message The question to ask the user
+    * @param html_button $buttoncontinue The html_button component representing the Continue answer
+    * @param html_button $buttoncancel The html_button component representing the Cancel answer
+    * @return string HTML fragment
+    */
+    public function confirm($message, $buttoncontinue, $buttoncancel) {
+        if (empty($buttoncontinue->label)) {
+            $buttoncontinue->label = get_string('yes');
+        }
+        if (empty($buttoncancel->label)) {
+            $buttoncancel->label = get_string('no');
+        }
+
+        $output = $this->box_start('generalbox', 'notice');
+        $output .= $this->output_tag('p', array(), $message);
+        $output .= $this->output_tag('div', array('class' => 'buttons'), $this->button($buttoncontinue) . $this->button($buttoncancel));
+        $output .= $this->box_end();
+        return $output;
+    }
+
+    /**
+     * Given a html_button object, outputs an <input> tag within a form that uses the object's attributes.
+     *
+     * @param html_button $button A html_button object
+     * @param string $formid An optional XHTML id attribute
+     * @return string HTML fragment
+     */
+    public function button($button, $formid=null) {
+        $button->prepare();
+        $this->page->prepare_event_handlers($button);
+
+        $buttonattributes = array('class' => $button->get_classes_string(),
+                                  'type' => 'submit',
+                                  'value' => $button->label);
+
+        $buttonattributes['disabled'] = $button->disabled;
+
+        if (empty($button->title) && !empty($popup->title)) {
+            $buttonattributes['title'] = $popup->title;
+        } else {
+            $buttonattributes['title'] = $button->title;
+        }
+
+        if (!empty($button->id)) {
+            $buttonattributes['id'] = $button->id;
+        }
+
+        $form = new html_form();
+        $form->url = $button->url;
+        $form->method = $button->method;
+        $form->id = $formid;
+
+        $buttonoutput = $this->output_empty_tag('input', $buttonattributes);
+        return $this->button_form($form, $buttonoutput);
+    }
+
+    /**
+     * Given a html_form component and an optional rendered submit button,
+     * outputs a HTML form with correct divs and inputs and a single submit button.
+     * This doesn't render any other visible inputs. Use moodleforms for these.
+     * @param html_form $form A html_form instance
+     * @param string $submitbutton A custom submit button (already rendered)
+     * @return string HTML fragment
+     */
+    public function button_form($form, $submitbutton=null) {
+        $form->prepare();
+        $this->page->prepare_event_handlers($form);
+
+        if (empty($submitbutton)) {
+            $submitbutton = $this->output_empty_tag('input', array('type' => 'submit', 'value' => get_string('ok')));
+        }
+
+        $hiddenoutput = '';
+
+        foreach ($form->url->params() as $var => $val) {
+            $hiddenoutput .= $this->output_empty_tag('input', array('type' => 'hidden', 'name' => $var, 'value' => $val));
+        }
+
+        $formattributes = array('method' => $form->method, 'action' => prepare_url($form->url, true));
+
+        $formattributes['id'] = $form->id;
+
+        $divoutput = $this->output_tag('div', array(), $hiddenoutput . $submitbutton);
+        $formoutput = $this->output_tag('form', $formattributes, $divoutput);
+        $output = $this->output_tag('div', array('class' => 'singlebutton'), $formoutput);
+
+        return $output;
+    }
+
+    /**
+     * Given a action_icon object, outputs an image linking to an action (URL or AJAX).
+     *
+     * @param action_icon $icon An action_icon object
+     * @return string HTML fragment
+     */
+    public function action_icon($icon) {
+
+        $icon->prepare();
+
+        $this->page->prepare_event_handlers($icon);
+
+        $image = new html_image();
+        $image->id = $icon->id;
+        $image->src = $icon->src;
+        $image->alt = $icon->title;
+
+        if (empty($image->alt) && !empty($icon->linktext)) {
+            $image->alt = $icon->linktext;
+        } else if (empty($image->alt)) {
+            debugging('action_icon called without correct $icon->title or $icon->linktext param given, no alt for the image.', DEBUG_DEVELOPER);
+        }
+
+        $image->add_classes($icon->classes);
+
+        $imageoutput = $this->image($image);
+
+        if ($icon->linktext) {
+            $imageoutput .= $icon->linktext;
+        }
+
+        $link = new html_link();
+        $link->url = $icon->url;
+        $link->text = $imageoutput;
+
+        return $this->link($link);
+    }
+
+    /**
+     * Print a help icon.
+     *
+     * @param help_icon $helpicon A help_icon object, subclass of html_link
+     *
+     * @return string  HTML fragment
+     */
+    public function help_icon($icon) {
+        global $COURSE;
+
+        $icon->prepare();
+
+        $icon->link->add_action_object(new popup_action('click', $icon->link->url));
+
+        $image = null;
+
+        if (!empty($icon->image)) {
+            $image = $icon->image;
+            $image->add_class('iconhelp');
+        }
+
+        return $this->output_tag('span', array('class' => 'helplink'), $this->link_to_popup($icon->link, $image));
+    }
+
+    /**
+     * Creates and returns a button to a popup window
+     *
+     * @param html_link $link Subclass of moodle_html_component
+     * @param moodle_popup $popup A moodle_popup object
+     * @param html_image $image An optional image replacing the link text
+     *
+     * @return string HTML fragment
+     */
+    public function link_to_popup($link, $image=null) {
+        $link->prepare();
+
+        $this->page->prepare_event_handlers($link);
+
+        if (empty($link->url)) {
+            throw new coding_exception('Called $OUTPUT->link_to_popup($link) method without $link->url set.');
+        }
+
+        $linkurl = prepare_url($link->url);
+
+        $tagoptions = array(
+                'title' => $link->title,
+                'id' => $link->id,
+                'href' => ($linkurl) ? $linkurl : prepare_url($popup->url),
+                'class' => $link->get_classes_string());
+
+        // Use image if one is given
+        if (!empty($image) && $image instanceof html_image) {
+
+            if (empty($image->alt)) {
+                $image->alt = $link->text;
+            }
+
+            $link->text = $this->image($image);
+
+            if (!empty($link->linktext)) {
+                $link->text = "$link->title &nbsp; $link->text";
+            }
+        }
+
+        return $this->output_tag('a', $tagoptions, $link->text);
+    }
+
+    /**
+     * Creates and returns a spacer image with optional line break.
+     *
+     * @param html_image $image Subclass of moodle_html_component
+     *
+     * @return string HTML fragment
+     */
+    public function spacer($image) {
+        $image->prepare();
+        $image->add_class('spacer');
+
+        if (empty($image->src)) {
+            $image->src = $this->old_icon_url('spacer');
+        }
+
+        $output = $this->image($image);
+
+        return $output;
+    }
+
+    /**
+     * Creates and returns an image.
+     *
+     * @param html_image $image Subclass of moodle_html_component
+     *
+     * @return string HTML fragment
+     */
+    public function image($image) {
+        $image->prepare();
+
+        $attributes = array('class' => $image->get_classes_string(),
+                            'style' => prepare_legacy_width_and_height($image),
+                            'src' => prepare_url($image->src),
+                            'alt' => $image->alt,
+                            'title' => $image->title);
+
+        return $this->output_empty_tag('img', $attributes);
+    }
+
+    /**
+     * Print the specified user's avatar.
+     *
+     * This method can be used in two ways:
+     * <pre>
+     * // Option 1:
+     * $userpic = new user_picture();
+     * // Set properties of $userpic
+     * $OUTPUT->user_picture($userpic);
+     *
+     * // Option 2: (shortcut for simple cases)
+     * // $user has come from the DB and has fields id, picture, imagealt, firstname and lastname
+     * $OUTPUT->user_picture($user, $COURSE->id);
+     * </pre>
+     *
+     * @param object $userpic Object with at least fields id, picture, imagealt, firstname, lastname
+     *     If any of these are missing, or if a userid is passed, the database is queried. Avoid this
+     *     if at all possible, particularly for reports. It is very bad for performance.
+     *     A user_picture object is a better parameter.
+     * @param int $courseid courseid Used when constructing the link to the user's profile. Required if $userpic
+     *     is not a user_picture object
+     * @return string HTML fragment
+     */
+    public function user_picture($userpic, $courseid=null) {
+        // Instantiate a user_picture object if $user is not already one
+        if (!($userpic instanceof user_picture)) {
+            if (empty($courseid)) {
+                throw new coding_exception('Called $OUTPUT->user_picture with a $user object but no $courseid.');
+            }
 
+            $user = $userpic;
+            $userpic = new user_picture();
+            $userpic->user = $user;
+            $userpic->courseid = $courseid;
-    }
+        }
 
-    public function button_to_popup_window() {
+        $userpic->prepare();
+
+        $output = $this->image($userpic->image);
 
+        if (!empty($userpic->link) && !empty($userpic->url)) {
+            $actions = $userpic->get_actions();
+            if (!empty($actions)) {
+                $link = new html_link();
+                $link->url = $userpic->url;
+                $link->text = fullname($userpic->user);
+                $link->add_action_object($actions[0]);
+                $output = $this->link_to_popup($link);
+            } else {
+                $output = $this->link(prepare_url($userpic->url), $output);
+            }
+        }
+
+        return $output;
     }
 
     public function close_window_button($buttontext = null, $reloadopener = false) {
@@ -2506,8 +2835,55 @@
         if (!is_a($link, 'moodle_url')) {
             $link = new moodle_url($link);
         }
-        return $this->output_tag('div', array('class' => 'continuebutton'),
-                print_single_button($link->out(true), $link->params(), get_string('continue'), 'get', '', true));
+        $button = new html_button();
+        $button->url = $link;
+        $button->values = $link->params();
+        $button->label = get_string('continue');
+        $button->method = 'get';
+
+        return $this->output_tag('div', array('class' => 'continuebutton') , $this->button($button));
+    }
+
+    /**
+     * Print a continue button that goes to a particular URL.
+     *
+     * @param string|moodle_url $link The url the button goes to.
+     * @return string the HTML to output.
+     */
+    public function paging_bar($pagingbar) {
+        $output = '';
+
+        $pagingbar->prepare();
+
+        if ($pagingbar->totalcount > $pagingbar->perpage) {
+            $output .= get_string('page') . ':';
+
+            if (!empty($pagingbar->previouslink)) {
+                $output .= '&nbsp;(' . $this->link($pagingbar->previouslink) . ')&nbsp;';
+            }
+
+            if (!empty($pagingbar->firstlink)) {
+                $output .= '&nbsp;' . $this->link($pagingbar->firstlink) . '&nbsp;...';
+            }
+
+            foreach ($pagingbar->pagelinks as $link) {
+                if ($link instanceof html_link) {
+                    $output .= '&nbsp;&nbsp;' . $this->link($link);
+                } else {
+                    $output .= "&nbsp;&nbsp;$link";
+                }
+            }
+
+            if (!empty($pagingbar->lastlink)) {
+                $output .= '&nbsp;...' . $this->link($pagingbar->lastlink) . '&nbsp;';
+            }
+
+            if (!empty($pagingbar->nextlink)) {
+                $output .= '&nbsp;&nbsp;(' . $this->link($pagingbar->nextlink) . ')';
+            }
+        }
+
+        return $this->output_tag('div', array('class' => 'paging'), $output);
     }
 
     /**
@@ -2730,6 +3106,20 @@
      * @var array class names to add to this HTML element.
      */
     public $classes = array();
+    /**
+     * @var string $title The title attributes applicable to any XHTML element
+     */
+    public $title = '';
+    /**
+     * An optional array of component_action objects handling the action part of this component.
+     * @var array $actions
+     */
+    protected $actions = array();
+    /**
+     * This array of generated ids is kept static to avoid id collisions
+     * @var array $generated_ids
+     */
+    public static $generated_ids = array();
 
     /**
      * Ensure some class names are an array.
@@ -2807,6 +3197,59 @@
         }
     }
 
+    /**
+     * Adds a JS action to this component.
+     * Note: the JS function you write must have only two arguments: (string)event and (object|array)args
+     * If you want to add an instantiated component_action (or one of its subclasses), use $component->add_action_object($action)
+     *
+     * @param string $event a DOM event (click, mouseover etc.)
+     * @param string $jsfunction The name of the JS function to call
+     * @param array  $jsfunctionargs An optional array of JS arguments to pass to the function
+     * @return void
+     */
+    public function add_action($event, $jsfunction, $jsfunctionargs=array()) {
+        while (empty($this->id) || in_array($this->id, moodle_html_component::$generated_ids)) {
+            $this->generate_id();
+        }
+        $this->actions[] = new component_action($event, $jsfunction, $jsfunctionargs);
+    }
+
+    /**
+     * Adds an instantiated component_action to this component.
+     * Note: the JS function you write must have only two arguments: (string)event and (object|array)args
+     *
+     * @param component_action $action An instantiated component_action or one of its subclasses
+     * @return void
+     */
+    public function add_action_object($action) {
+        if (!($action instanceof component_action)) {
+            throw new coding_exception('moodle_html_component::add_action_object($action) only takes an instance of component_action.');
+        }
+
+        while (empty($this->id) && !in_array($this->id, moodle_html_component::$generated_ids)) {
+            $this->generate_id();
+        }
+        $this->actions[] = $action;
+    }
+
+    /**
+     * Internal method for generating a unique ID for the purpose of event handlers.
+     * @return void;
+     */
+    protected function generate_id() {
+        $this->id = get_class($this) . '-' . substr(sha1(microtime() * rand(0, 500)), 0, 5);
+        if (!in_array($this->id, moodle_html_component::$generated_ids)) {
+            moodle_html_component::$generated_ids[] = $this->id;
+        }
+    }
+
+    /**
+     * Returns the array of component_actions.
+     * @return array Component actions
+     */
+    public function get_actions() {
+        return $this->actions;
+    }
 }
 
 
@@ -3229,6 +3672,726 @@
     }
 }
 
+/**
+ * Component representing a XHTML link.
+ *
+ * @copyright 2009 Nicolas Connault
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since     Moodle 2.0
+ */
+class html_link extends moodle_html_component {
+    /**
+     * URL can be simple text or a moodle_url object
+     * @var mixed $url
+     */
+    public $url;
+
+    /**
+     * @var string $text The text that will appear between the link tags
+     */
+    public $text;
+
+    /* @see lib/moodle_html_component#prepare() */
+    public function prepare() {
+        // We can't accept an empty text value
+        if (empty($this->text)) {
+            throw new coding_exception('A html_link must have a descriptive text value!');
+        }
+
+        parent::prepare();
+    }
+}
+
+/**
+ * Component representing a help icon.
+ *
+ * @copyright 2009 Nicolas Connault
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since     Moodle 2.0
+ */
+class help_icon extends moodle_html_component {
+    /**
+     * @var html_link $link A html_link object that will hold the URL info
+     */
+    public $link;
+    /**
+     * @var string $text A descriptive text
+     */
+    public $text;
+    /**
+     * @var string $page  The keyword that defines a help page
+     */
+    public $page;
+    /**
+     * @var string $module Which module is the page defined in
+     */
+    public $module = 'moodle';
+    /**
+     * @var boolean $linktext Whether or not to show text next to the icon
+     */
+    public $linktext = false;
+    /**
+     * @var mixed $image The help icon. Can be set to true (will use default help icon),
+     *                   false (will not use any icon), the URL to an image, or a full
+     *                   html_image object.
+     */
+    public $image;
+
+    public function prepare() {
+        global $COURSE, $OUTPUT;
+
+        if (empty($this->page)) {
+            throw new coding_exception('A help_icon object requires a $page parameter');
+        }
+
+        if (empty($this->text)) {
+            throw new coding_exception('A help_icon object requires a $text parameter');
+        }
+
+        $this->link = new html_link();
+        $this->link->text = $this->text;
+
+        // fix for MDL-7734
+        $this->link->url = new moodle_url('/help.php', array('module' => $this->module, 'file' => $this->page .'.html'));
+
+        // fix for MDL-7734
+        if (!empty($COURSE->lang)) {
+            $this->link->url->param('forcelang', $COURSE->lang);
+        }
+
+        // Catch references to the old text.html and emoticons.html help files that
+        // were renamed in MDL-13233.
+        if (in_array($this->page, array('text', 'emoticons', 'richtext'))) {
+            $oldname = $this->page;
+            $this->page .= '2';
+            debugging("You are referring to the old help file '$oldname'. " .
+                    "This was renamed to '$this->page' because of MDL-13233. " .
+                    "Please update your code.", DEBUG_DEVELOPER);
+        }
+
+        if ($this->module == '') {
+            $this->module = 'moodle';
+        }
+
+        // Warn users about new window for Accessibility
+        $this->title = get_string('helpprefix2', '', trim($this->text, ". \t")) .' ('.get_string('newwindow').')';
+
+        // Prepare image and linktext
+        if ($this->image && !($this->image instanceof html_image)) {
+            $image = fullclone($this->image);
+            $this->image = new html_image();
+
+            if ($image instanceof moodle_url) {
+                $this->image->src = $image->out();
+            } else if ($image === true) {
+                $this->image->src = $OUTPUT->old_icon_url('help');
+            } else if (is_string($image)) {
+                $this->image->src = $image;
+            }
+            $this->image->alt = $this->text;
+
+            if ($this->linktext) {
+                $this->image->alt = get_string('helpwiththis');
+            } else {
+                $this->image->alt = $this->title;
+            }
+            $this->image->add_class('iconhelp');
+        }
+
+        parent::prepare();
+    }
+}
+
+/**
+ * Helper class used by other components that involve an action on the page (URL or JS).
+ *
+ * @copyright 2009 Nicolas Connault
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since     Moodle 2.0
+ */
+class component_action {
+
+    /**
+     * The DOM event that will trigger this action when caught
+     * @var string $event DOM event
+     */
+    public $event;
+
+    /**
+     * The JS function you create must have two arguments:
+     *      1. The event object
+     *      2. An object/array of arguments ($jsfunctionargs)
+     * @var string $jsfunction A function name to call when the button is clicked
+     */
+    public $jsfunction = false;
+
+    /**
+     * @var array $jsfunctionargs An array of arguments to pass to the JS function
+     */
+    public $jsfunctionargs = array();
+
+    /**
+     * Constructor
+     * @param string $event DOM event
+     * @param moodle_url $url A moodle_url object, required if no jsfunction is given
+     * @param string $method 'post' or 'get'
+     * @param string $jsfunction An optional JS function. Required if jsfunctionargs is given
+     * @param array  $jsfunctionargs An array of arguments to pass to the jsfunction
+     * @return void
+     */
+    public function __construct($event, $jsfunction, $jsfunctionargs=array()) {
+        $this->event = $event;
+
+        $this->jsfunction = $jsfunction;
+        $this->jsfunctionargs = $jsfunctionargs;
+
+        if (!empty($this->jsfunctionargs)) {
+            if (empty($this->jsfunction)) {
+                throw new coding_exception('The component_action object needs a jsfunction value to pass the jsfunctionargs to.');
+            }
+        }
+    }
+}
+
+/**
+ * Component action for a popup window.
+ *
+ * @copyright 2009 Nicolas Connault
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since     Moodle 2.0
+ */
+class popup_action extends component_action {
+    /**
+     * @var array $params An array of parameters that will be passed to the openpopup JS function
+     */
+    public $params = array(
+            'height' =>  400,
+            'width' => 500,
+            'top' => 0,
+            'left' => 0,
+            'menubar' => false,
+            'location' => false,
+            'scrollbars' => true,
+            'resizable' => true,
+            'toolbar' => true,
+            'status' => true,
+            'directories' => false,
+            'fullscreen' => false,
+            'dependent' => true);
+
+    /**
+     * Constructor
+     * @param string $event DOM event
+     * @param moodle_url $url A moodle_url object, required if no jsfunction is given
+     * @param string $method 'post' or 'get'
+     * @param array  $params An array of popup parameters
+     * @return void
+     */
+    public function __construct($event, $url, $name='popup', $params=array()) {
+        global $CFG;
+        $this->name = $name;
+
+        $url = new moodle_url($url);
+
+        if ($this->name) {
+            $_name = $this->name;
+            if (($_name = preg_replace("/\s/", '_', $_name)) != $this->name) {
+                throw new coding_exception('The $name of a popup window shouldn\'t contain spaces - string modified. '. $this->name .' changed to '. $_name);
+                $this->name = $_name;
+            }
+        } else {
+            $this->name = 'popup';
+        }
+
+        foreach ($this->params as $var => $val) {
+            if (array_key_exists($var, $params)) {
+                $this->params[$var] = $params[$var];
+            }
+        }
+        parent::__construct($event, 'openpopup', array('url' => $url->out(false, array(), false), 'name' => $name, 'options' => $this->get_js_options($params)));
+    }
+
+    /**
+     * Returns a string of concatenated option->value pairs used by JS to call the popup window,
+     * based on this object's variables
+     *
+     * @return string String of option->value pairs for JS popup function.
+     */
+    public function get_js_options() {
+        $jsoptions = '';
+
+        foreach ($this->params as $var => $val) {
+            if (is_string($val) || is_int($val)) {
+                $jsoptions .= "$var=$val,";
+            } elseif (is_bool($val)) {
+                $jsoptions .= ($val) ? "$var," : "$var=0,";
+            }
+        }
+
+        $jsoptions = substr($jsoptions, 0, strlen($jsoptions) - 1);
+
+        return $jsoptions;
+    }
+}
+
+
+/**
+ * Component representing a XHTML button (input of type 'button').
+ * The renderer will either output it as a button with an onclick event,
+ * or as a form with hidden inputs.
+ *
+ * @copyright 2009 Nicolas Connault
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since     Moodle 2.0
+ */
+class html_button extends moodle_html_component {
+    /**
+     * This URL is used only to set up the component_action associated
+     * with this button. Do not use this value in the renderer!
+     * @var mixed $url A string or a moodle_url object
+     */
+    public $url;
+
+    /**
+     * @var string $label
+     */
+    public $label;
+
+    /**
+     * @var boolean $disabled Whether or not this button is disabled
+     */
+    public $disabled = false;
+
+    /**
+     * @var string $method post or get
+     */
+    public $method = 'post';
+
+    /* @see lib/moodle_html_component#prepare() */
+    public function prepare() {
+        $this->add_class('singlebutton');
+
+        if (empty($this->label)) {
+            throw new coding_exception('A html_button must have a label value!');
+        }
+
+        if (empty($this->url)) {
+            throw new coding_exception('A html_button must have a url value!');
+        }
+
+        if ($this->disabled) {
+            $this->disabled = 'disabled';
+        }
+
+        $this->url = new moodle_url($this->url);
+
+        parent::prepare();
+    }
+}
+
+/**
+ * Component representing an icon linking to a Moodle page.
+ *
+ * @copyright 2009 Nicolas Connault
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since     Moodle 2.0
+ */
+class action_icon extends moodle_html_component {
+    /**
+     * @var mixed $url A string or a moodle_url object
+     */
+    public $url;
+    /**
+     * @var string $title A descriptive text
+     */
+    public $title;
+    /**
+     * @var string $src The path to the image being used
+     */
+    public $src;
+    /**
+     * @var string $linktext Optional text to display next to the icon
+     */
+    public $linktext;
+
+    /**
+     * @var string $method post or get
+     */
+    public $method = 'post';
+
+    public function prepare() {
+        $this->add_class('action-icon');
+
+        parent::prepare();
+
+        if (empty($this->src)) {
+            throw new coding_exception('An action_icon object requires a $src value for its image');
+        }
+    }
+}
+
+/**
+ * Component representing an image.
+ *
+ * @copyright 2009 Nicolas Connault
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since     Moodle 2.0
+ */
+class html_image extends moodle_html_component {
+    /**
+     * @var string $alt A descriptive text
+     */
+    public $alt = HTML_ATTR_EMPTY;
+    /**
+     * @var string $src The path to the image being used
+     */
+    public $src;
+
+    public function prepare() {
+        $this->add_class('image');
+        parent::prepare();
+    }
+}
+
+/**
+ * Component representing a user picture.
+ *
+ * @copyright 2009 Nicolas Connault
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since     Moodle 2.0
+ */
+class user_picture extends moodle_html_component {
+    /**
+     * @var mixed $user A userid or a user object with at least fields id, picture, imagealrt, firstname and lastname set.
+     */
+    public $user;
+    /**
+     * @var int $courseid The course id. Used when constructing the link to the user's profile.
+     */
+    public $courseid;
+    /**
+     * @var html_image $image A custom image used as the user picture.
+     */
+    public $image;
+    /**
+     * @var mixed $url False: picture not enclosed in a link. True: default link. moodle_url: custom link.
+     */
+    public $url;
+    /**
+     * @var int $size Size in pixels. Special values are (true/1 = 100px) and (false/0 = 35px) for backward compatibility
+     */
+    public $size;
+    /**
+     * @var boolean $alttext add non-blank alt-text to the image. (Default true, set to false for purely
+     */
+    public $alttext = true;
+
+    public function prepare() {
+        global $CFG, $DB, $OUTPUT;
+
+        if (empty($this->user)) {
+            throw new coding_exception('A user_picture object must have a $user object before being rendered.');
+        }
+
+        if (empty($this->courseid)) {
+            throw new coding_exception('A user_picture object must have a courseid value before being rendered.');
+        }
+
+        if (empty($this->image)) {
+            $this->image = new html_image();
+        } else if (!($this->image instanceof html_image)) {
+            debugging('user_picture::image must be an instance of html_image', DEBUG_DEVELOPER);
+        }
+
+        $needrec = false;
+        // only touch the DB if we are missing data...
+        if (is_object($this->user)) {
+            // Note - both picture and imagealt _can_ be empty
+            // what we are trying to see here is if they have been fetched
+            // from the DB. We should use isset() _except_ that some installs
+            // have those fields as nullable, and isset() will return false
+            // on null. The only safe thing is to ask array_key_exists()
+            // which works on objects. property_exists() isn't quite
+            // what we want here...
+            if (! (array_key_exists('picture', $this->user)
+                   && ($this->alttext && array_key_exists('imagealt', $this->user)
+                       || (isset($this->user->firstname) && isset($this->user->lastname)))) ) {
+                $needrec = true;
+                $this->user = $this->user->id;
+            }
+        } else {
+            if ($this->alttext) {
+                // we need firstname, lastname, imagealt, can't escape...
+                $needrec = true;
+            } else {
+                $userobj = new StdClass; // fake it to save DB traffic
+                $userobj->id = $user;
+                $userobj->picture = $picture;
+                $this->user = clone($userobj);
+                unset($userobj);
+            }
+        }
+        if ($needrec) {
+            $this->user = $DB->get_record('user', array('id' => $this->user), 'id,firstname,lastname,imagealt');
+        }
+
+        if (!empty($this->link) && empty($this->url)) {
+            $this->url = new moodle_url('/user/view.php', array('id' => $this->user->id, 'course' => $this->courseid));
+        }
+
+        if (empty($this->size)) {
+            $file = 'f2';
+            $this->size = 35;
+        } else if ($this->size === true or $this->size == 1) {
+            $file = 'f1';
+            $this->size = 100;
+        } else if ($this->size >= 50) {
+            $file = 'f1';
+        } else {
+            $file = 'f2';
+        }
+
+        $this->add_class('userpicture');
+
+        if (empty($this->image->src)) {
+            $this->image->src = $this->user->picture;
+        }
+
+        if (!empty($this->image->src)) {
+            require_once($CFG->libdir.'/filelib.php');
+            $this->image->src = new moodle_url(get_file_url($this->user->id.'/'.$file.'.jpg', null, 'user'));
+        } else { // Print default user pictures (use theme version if available)
+            $this->add_class('defaultuserpic');
+            $this->image->src = $OUTPUT->old_icon_url('u/' . $file);
+        }
+
+        if ($this->alttext) {
+            if (!empty($this->user->imagealt)) {
+                $this->image->alt = $this->user->imagealt;
+            } else {
+                $this->image->alt = get_string('pictureof','',fullname($this->user));
+            }
+        }
+
+        parent::prepare();
+    }
+}
+
+/**
+ * Component representing a textarea.
+ *
+ * @copyright 2009 Nicolas Connault
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since     Moodle 2.0
+ */
+class html_textarea extends moodle_html_component {
+    /**
+     * @param string $name Name to use for the textarea element.
+     */
+    public $name;
+    /**
+     * @param string $value Initial content to display in the textarea.
+     */
+    public $value;
+    /**
+     * @param int $rows Number of rows to display  (minimum of 10 when $height is non-null)
+     */
+    public $rows;
+    /**
+     * @param int $cols Number of columns to display (minimum of 65 when $width is non-null)
+     */
+    public $cols;
+    /**
+     * @param bool $usehtmleditor Enables the use of the htmleditor for this field.
+     */
+    public $usehtmleditor;
+
+    public function prepare() {
+        $this->add_class('form-textarea');
+
+        if (empty($this->id)) {
+            $this->id = "edit-$this->name";
+        }
+
+        if ($this->usehtmleditor) {
+            editors_head_setup();
+            $editor = get_preferred_texteditor(FORMAT_HTML);
+            $editor->use_editor($this->id, array('legacy'=>true));
+            $this->value = htmlspecialchars($value);
+        }
+
+        parent::prepare();
+    }
+}
+
+/**
+ * Component representing a simple form wrapper. Its purpose is mainly to enclose
+ * a submit input with the appropriate action and hidden inputs.
+ *
+ * @copyright 2009 Nicolas Connault
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since     Moodle 2.0
+ */
+class html_form extends moodle_html_component {
+    /**
+     * @var string $method post or get
+     */
+    public $method = 'post';
+    /**
+     * If a string is given, it will be converted to a moodle_url during prepare()
+     * @var mixed $url A moodle_url including params or a string
+     */
+    public $url;
+    /**
+     * @var array $params Optional array of parameters. Ignored if $url instanceof moodle_url
+     */
+    public $params = array();
+
+    public function prepare() {
+        if (empty($this->url)) {
+            throw new coding_exception('A html_form must have a $url value (string or moodle_url).');
+        }
+
+        if (!($this->url instanceof moodle_url)) {
+            $this->url = new moodle_url($this->url, $this->params);
+        }
+
+        if ($this->method == 'post') {
+            $this->url->param('sesskey', sesskey());
+        }
+        parent::prepare();
+    }
+}
+
+/**
+ * Component representing a paging bar.
+ *
+ * @copyright 2009 Nicolas Connault
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since     Moodle 2.0
+ */
+class html_paging_bar extends moodle_html_component {
+    /**
+     * @var int $maxdisplay The maximum number of pagelinks to display
+     */
+    public $maxdisplay = 18;
+    /**
+     * @var int $totalcount post or get
+     */
+    public $totalcount;
+    /**
+     * @var int $page The page you are currently viewing
+     */
+    public $page;
+    /**
+     * @var int $perpage The number of entries that should be shown per page
+     */
+    public $perpage;
+    /**
+     * @var $baseurl If this  is a string then it is the url which will be appended with $pagevar, an equals sign and the page number.
+     *      If this is a moodle_url object then the pagevar param will be replaced by the page no, for each page.
+     */
+    public $baseurl;
+    /**
+     * @var string $pagevar This is the variable name that you use for the page number in your code (ie. 'tablepage', 'blogpage', etc)
+     */
+    public $pagevar = 'page';
+    /**
+     * @var bool $nocurr do not display the current page as a link
+     */
+    public $nocurr;
+    /**
+     * @var html_link $previouslink A HTML link representing the "previous" page
+     */
+    public $previouslink = null;
+    /**
+     * @var html_link $nextlink A HTML link representing the "next" page
+     */
+    public $nextlink = null;
+    /**
+     * @var html_link $firstlink A HTML link representing the first page
+     */
+    public $firstlink = null;
+    /**
+     * @var html_link $lastlink A HTML link representing the last page
+     */
+    public $lastlink = null;
+    /**
+     * @var array $pagelinks An array of html_links. One of them is just a string: the current page
+     */
+    public $pagelinks = array();
+
+    public function prepare() {
+        if (!($this->baseurl instanceof moodle_url)) {
+            $this->baseurl = new moodle_url($this->baseurl);
+        }
+
+        if ($this->totalcount > $this->perpage) {
+            $pagenum = $this->page - 1;
+
+            if ($this->page > 0) {
+                $this->previouslink = new html_link();
+                $this->previouslink->add_class('previous');
+                $this->previouslink->url = $this->baseurl->out(false, array($this->pagevar => $pagenum));
+                $this->previouslink->text = get_string('previous');
+            }
+
+            if ($this->perpage > 0) {
+                $lastpage = ceil($this->totalcount / $this->perpage);
+            } else {
+                $lastpage = 1;
+            }
+
+            if ($this->page > 15) {
+                $startpage = $this->page - 10;
+
+                $this->firstlink = new html_link();
+                $this->firstlink->url = $this->baseurl->out(false, array($this->pagevar => 0));
+                $this->firstlink->text = 1;
+                $this->firstlink->add_class('first');
+            } else {
+                $startpage = 0;
+            }
+
+            $currpage = $startpage;
+            $displaycount = $displaypage = 0;
+
+            while ($displaycount < $this->maxdisplay and $currpage < $lastpage) {
+                $displaypage = $currpage + 1;
+
+                if ($this->page == $currpage && empty($this->nocurr)) {
+                    $this->pagelinks[] = $displaypage;
+                } else {
+                    $pagelink = new html_link();
+                    $pagelink->url = $this->baseurl->out(false, array($this->pagevar => $currpage));
+                    $pagelink->text = $displaypage;
+                    $this->pagelinks[] = $pagelink;
+                }
+
+                $displaycount++;
+                $currpage++;
+            }
+
+            if ($currpage < $lastpage) {
+                $lastpageactual = $lastpage - 1;
+                $this->lastlink = new html_link();
+                $this->lastlink->url = $this->baseurl->out(false, array($this->pagevar => $lastpageactual));
+                $this->lastlink->text = $lastpage;
+                $this->lastlink->add_class('last');
+            }
+
+            $pagenum = $this->page + 1;
+
+            if ($pagenum != $displaypage) {
+                $this->nextlink = new html_link();
+                $this->nextlink->url = $this->baseurl->out(false, array($this->pagevar => $pagenum));
+                $this->nextlink->text = get_string('next');
+                $this->nextlink->add_class('next');
+            }
+        }
+    }
+
+}
 
 /**
  * A renderer that generates output for command-line scripts.
@@ -3423,3 +4586,23 @@
         echo "/* @end */\n\n";
     }
 }
+
+/**
+ * Given a moodle_html_component with height and/or width set, translates them
+ * to appropriate CSS rules.
+ *
+ * @param moodle_html_component $component
+ * @return string CSS rules
+ */
+function prepare_legacy_width_and_height($component) {
+    $output = '';
+    if (!empty($component->height)) {
+        debugging('Explicit height given to moodle_html_component leads to inline css. Use a proper CSS class instead.', DEBUG_DEVELOPER);
+        $output = "height: {$component->height}px;";
+    }
+    if (!empty($component->width)) {
+        debugging('Explicit width given to moodle_html_component leads to inline css. Use a proper CSS class instead.', DEBUG_DEVELOPER);
+        $output .= "width: {$component->width}px;";
+    }
+    return $output;
+}
Index: lib/pagelib.php
=========================================================
--- lib/pagelib.php	(revision 1.143)
+++ lib/pagelib.php	Sat Jul 25 10:31:14 WST 2009
@@ -1367,6 +1367,25 @@
     function get_modulerecord() {
         return $this->cm;
     }
+
+    /**
+     * A helper function that takes a moodle_html_component subclass as param.
+     * If that component has an id attribute and an array of valid component_action objects,
+     * it sets up the appropriate event handlers.
+     *
+     * @param moodle_html_component $component
+     * @return void;
+     */
+    public function prepare_event_handlers(&$component) {
+        $actions = $component->get_actions();
+        if (!empty($actions) && is_array($actions) && $actions[0] instanceof component_action) {
+            foreach ($actions as $action) {
+                if (!empty($action->jsfunction)) {
+                    $this->requires->event_handler($component->id, $action->event, $action->jsfunction, $action->jsfunctionargs);
+                }
+            }
+        }
+    }
 }
 
 /**
Index: lib/simpletest/testdeprecatedlib.php
=========================================================
--- lib/simpletest/testdeprecatedlib.php	(revision 0)
+++ lib/simpletest/testdeprecatedlib.php	Fri Jul 24 22:01:50 WST 2009
@@ -0,0 +1,74 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+
+/**
+ * Unit tests for ../deprecatedlib.php.
+ *
+ * @package   moodlecore
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later (5)
+ */
+
+if (!defined('MOODLE_INTERNAL')) {
+    die('Direct access to this script is forbidden.');    ///  It must be included from a Moodle page
+}
+require_once($CFG->libdir . '/deprecatedlib.php');
+
+class outputlib_methods_test extends UnitTestCase {
+    public function test_print_single_button() {
+        global $PAGE, $CFG;
+
+        // Basic params, absolute URL
+        $link = 'http://www.test.com/index.php';
+        $options = array('param1' => 'value1');
+        $label = 'OK';
+        $method = 'get';
+        $return = true;
+        $tooltip = '';
+        $disabled = false;
+        $jsconfirmmessage = '';
+        $formid = '';
+
+        $html = print_single_button($link, $options, $label, $method, '', $return, $tooltip, $disabled, $jsconfirmmessage, $formid);
+        $this->assert(new ContainsTagWithAttributes('form', array('method' => $method, 'action' => $link)), $html);
+        $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'param1', 'value' => 'value1')), $html);
+        $this->assert(new ContainsTagWithAttributes('input', array('type' => 'submit', 'value' => 'OK')), $html);
+
+        // URL with &amp; params
+        $newlink = $link . '?param1=value1&amp;param2=value2';
+        $html = print_single_button($newlink, $options, $label, $method, '', $return, $tooltip, $disabled, $jsconfirmmessage, $formid);
+        $this->assert(new ContainsTagWithAttributes('form', array('method' => $method, 'action' => $link)), $html);
+        $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'param1', 'value' => 'value1')), $html);
+        $this->assert(new ContainsTagWithAttributes('input', array('type' => 'submit', 'value' => 'OK')), $html);
+
+        // URL with & params
+        $newlink = $link . '?param1=value1&param2=value2';
+        $html = print_single_button($newlink, $options, $label, $method, '', $return, $tooltip, $disabled, $jsconfirmmessage, $formid);
+        $this->assert(new ContainsTagWithAttributes('form', array('method' => $method, 'action' => $link)), $html);
+        $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'param1', 'value' => 'value1')), $html);
+        $this->assert(new ContainsTagWithAttributes('input', array('type' => 'submit', 'value' => 'OK')), $html);
+
+        // relative URL with & params
+        $newlink = 'index.php?param1=value1&param2=value2';
+        $PAGE->set_url('index.php');
+        $html = print_single_button($newlink, $options, $label, $method, '', $return, $tooltip, $disabled, $jsconfirmmessage, $formid);
+        $this->assert(new ContainsTagWithAttributes('form', array('method' => $method, 'action' => $CFG->wwwroot . '/index.php')), $html);
+        $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'param1', 'value' => 'value1')), $html);
+        $this->assert(new ContainsTagWithAttributes('input', array('type' => 'submit', 'value' => 'OK')), $html);
+    }
+}
Index: lib/simpletest/testoutputlib.php
=========================================================
--- lib/simpletest/testoutputlib.php	(revision 1.8)
+++ lib/simpletest/testoutputlib.php	Sat Jul 25 10:36:32 WST 2009
@@ -578,7 +578,7 @@
         $this->make_theme_template_dir('mytheme');
         $this->make_theme_template_dir('parenttheme');
         $this->make_theme_template_dir('standardtemplate');
-                
+
         // Exercise SUT.
         $factory = new testable_template_renderer_factory($theme, $this->page);
 
@@ -597,7 +597,7 @@
         $theme->parent = 'parenttheme';
         $this->make_theme_template_dir('mytheme');
         $this->make_theme_template_dir('standardtemplate');
-                
+
         // Exercise SUT.
         $factory    = new testable_template_renderer_factory($theme, $this->page);
         $subfactory = new testable_template_renderer_factory($theme, $this->page, 'subtype');
@@ -905,4 +905,135 @@
         $html = $this->renderer->error_text('');
         $this->assertEqual('', $html);
     }
+
+    public function test_link_to_popup_empty_link() {
+        // Empty link object: link MUST have a text value
+        $link = new html_link();
+        $popupaction = new popup_action('click', 'http://test.com', 'my_popup');
+        $link->add_action_object($popupaction);
+        $this->expectException();
+        $html = $this->renderer->link_to_popup($link);
+    }
+
+    public function test_link_to_popup() {
+        $link = new html_link();
+        $link->text = 'Click here';
+        $link->url = 'http://test.com';
+        $link->title = 'Popup window';
+        $popupaction = new popup_action('click', 'http://test.com', 'my_popup');
+        $link->add_action_object($popupaction);
+
+        $html = $this->renderer->link_to_popup($link);
+        $expectedattributes = array('title' => 'Popup window', 'href' => 'http://test.com');
+        $this->assert(new ContainsTagWithAttributes('a', $expectedattributes), $html);
+        $this->assert(new ContainsTagWithContents('a', 'Click here'), $html);
+
+        // Try a different url for the link than for the popup
+        $link->url = 'http://otheraddress.com';
+        $html = $this->renderer->link_to_popup($link);
+
+        $this->assert(new ContainsTagWithAttribute('a', 'title', 'Popup window'), $html);
+        $this->assert(new ContainsTagWithAttribute('a', 'href', 'http://otheraddress.com'), $html);
+        $this->assert(new ContainsTagWithContents('a', 'Click here'), $html);
+
+        // Give it a moodle_url object instead of a string
+        $link->url = new moodle_url('http://otheraddress.com');
+        $html = $this->renderer->link_to_popup($link);
+        $this->assert(new ContainsTagWithAttribute('a', 'title', 'Popup window'), $html);
+        $this->assert(new ContainsTagWithAttribute('a', 'href', 'http://otheraddress.com'), $html);
+        $this->assert(new ContainsTagWithContents('a', 'Click here'), $html);
+
+    }
+
+    public function test_button() {
+        global $CFG;
+        $button = new html_button();
+        $button->label = 'Click Here';
+        $button->url = '/index.php';
+
+        $html = $this->renderer->button($button);
+        $this->assert(new ContainsTagWithAttribute('div', 'class', 'singlebutton'), $html);
+        $this->assert(new ContainsTagWithAttributes('form', array('method' => 'post', 'action' => $CFG->wwwroot . '/index.php')), $html);
+        $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey())), $html);
+        $this->assert(new ContainsTagWithAttributes('input', array('value' => 'Click Here', 'type' => 'submit')), $html);
+
+        $button = new html_button();
+        $button->label = 'Click Here';
+        $button->url = '/index.php';
+        $button->confirmmessage = 'Are you sure?';
+
+        $html = $this->renderer->button($button);
+        $this->assert(new ContainsTagWithAttribute('div', 'class', 'singlebutton'), $html);
+        $this->assert(new ContainsTagWithAttributes('form', array('method' => 'post', 'action' => $CFG->wwwroot . '/index.php')), $html);
+        $this->assert(new ContainsTagWithAttribute('input', 'type', 'submit'), $html);
+
+        $button = new html_button();
+        $button->label = 'Click Here';
+        $button->url = '/index.php';
+        $button->url = new moodle_url($button->url, array('var1' => 'value1', 'var2' => 'value2'));
+        $html = $this->renderer->button($button);
+        $this->assert(new ContainsTagWithAttributes('input', array('name' => 'var1', 'type' => 'hidden', 'value' => 'value1')), $html);
+
+    }
+
+    public function test_link() {
+        $link = new html_link();
+        $link->url = 'http://test.com';
+        $link->text = 'Resource 1';
+
+        $html = $this->renderer->link($link);
+        $this->assert(new ContainsTagWithAttribute('a', 'href', 'http://test.com'), $html);
+        $this->assert(new ContainsTagWithContents('a', 'Resource 1'), $html);
+
+        // Add a title
+        $link->title = 'Link to resource 1';
+        $html = $this->renderer->link($link);
+        $this->assert(new ContainsTagWithAttributes('a', array('title' => 'Link to resource 1', 'href' => 'http://test.com')), $html);
+        $this->assert(new ContainsTagWithContents('a', 'Resource 1'), $html);
+
+        // Use a moodle_url object instead of string
+        $link->url = new moodle_url($link->url);
+        $html = $this->renderer->link($link);
+        $this->assert(new ContainsTagWithAttributes('a', array('title' => 'Link to resource 1', 'href' => 'http://test.com')), $html);
+        $this->assert(new ContainsTagWithContents('a', 'Resource 1'), $html);
+
+        // Add a few classes to the link object
+        $link->add_classes('cool blue');
+        $html = $this->renderer->link($link);
+        $this->assert(new ContainsTagWithAttributes('a', array('title' => 'Link to resource 1', 'class' => 'link cool blue', 'href' => 'http://test.com')), $html);
+        $this->assert(new ContainsTagWithContents('a', 'Resource 1'), $html);
+
+        // Simple use of link() without a html_link object
+        $html = $this->renderer->link($link->url->out(), $link->text);
+        $expected_html = '<a href="http://test.com">Resource 1</a>';
+        $this->assert(new ContainsTagWithAttribute('a', 'href', 'http://test.com'), $html);
+        $this->assert(new ContainsTagWithContents('a', 'Resource 1'), $html);
+
+        // Missing second param when first is a string: exception
+        $this->expectException();
+        $html = $this->renderer->link($link->url->out());
+    }
+
+    public function test_spacer() {
+        global $CFG;
+
+        $spacer = new html_image();
+
+        $html = $this->renderer->spacer($spacer);
+        $this->assert(new ContainsTagWithAttributes('img', array('class' => 'image spacer',
+                 'src' => $CFG->wwwroot . '/pix/spacer.gif',
+                 'alt' => ''
+                 )), $html);
+        $spacer = new html_image();
+        $spacer->src = $this->renderer->old_icon_url('myspacer');
+        $spacer->alt = 'sometext';
+        $spacer->add_class('my');
+
+        $html = $this->renderer->spacer($spacer);
+
+        $this->assert(new ContainsTagWithAttributes('img', array('class' => 'my image spacer',
+                 'src' => $this->renderer->old_icon_url('myspacer'),
+                 'alt' => 'sometext')), $html);
+
+    }
 }
Index: lib/simpletest/testweblib.php
=========================================================
--- lib/simpletest/testweblib.php	(revision 1.15)
+++ lib/simpletest/testweblib.php	Thu Jul 23 11:27:42 WST 2009
@@ -70,7 +70,7 @@
         $this->assertEqual(highlight('good', 'This is goodness'), 'This is <span class="highlight">good</span>ness');
     }
 
-    function test_replace_ampersands() { 
+    function test_replace_ampersands() {
         $this->assertEqual(replace_ampersands_not_followed_by_entity("This & that &nbsp;"), "This &amp; that &nbsp;");
         $this->assertEqual(replace_ampersands_not_followed_by_entity("This &nbsp that &nbsp;"), "This &amp;nbsp that &nbsp;");
     }
@@ -92,10 +92,29 @@
         $string = "visit http://www.moodle.org";
         convert_urls_into_links($string);
         $this->assertEqual($string, 'visit <a href="http://www.moodle.org">http://www.moodle.org</a>');
-        
+
         $string = "visit www.moodle.org";
         convert_urls_into_links($string);
         $this->assertEqual($string, 'visit <a href="http://www.moodle.org">www.moodle.org</a>');
     }
+
+    function test_prepare_url() {
+        global $CFG, $PAGE;
+        $fullexternalurl = 'http://www.externalsite.com/somepage.php';
+        $fullmoodleurl = $CFG->wwwroot . '/mod/forum/view.php?id=5';
+        $relativeurl1 = 'edit.php';
+        $relativeurl2 = '/edit.php';
+
+        $this->assertEqual($fullmoodleurl, prepare_url($fullmoodleurl));
+        $this->assertEqual($fullexternalurl, prepare_url($fullexternalurl));
+        $this->assertEqual("$CFG->wwwroot/admin/report/unittest/$relativeurl1", prepare_url($relativeurl1));
+        $this->assertEqual("$CFG->wwwroot$relativeurl2", prepare_url($relativeurl2));
+
+        // Use moodle_url object
+        $this->assertEqual($fullmoodleurl, prepare_url(new moodle_url('/mod/forum/view.php', array('id' => 5))));
+        $this->assertEqual($fullexternalurl, prepare_url(new moodle_url($fullexternalurl)));
+        $this->assertEqual("$CFG->wwwroot/admin/report/unittest/$relativeurl1", prepare_url(new moodle_url($relativeurl1)));
+        $this->assertEqual("$CFG->wwwroot$relativeurl2", prepare_url(new moodle_url($relativeurl2)));
+    }
 }
 ?>
Index: lib/simpletestlib.php
=========================================================
--- lib/simpletestlib.php	(revision 1.37)
+++ lib/simpletestlib.php	Fri Jul 24 19:36:09 WST 2009
@@ -256,13 +256,13 @@
             }
 
             $result = true;
-
+            
             foreach ($this->attributes as $attribute => $expectedvalue) {
-                if (!$node->attributes->getNamedItem($attribute)) {
+                if (!$node->getAttribute($attribute)) {
                     break 2;
                 }
                 
-                if ($node->attributes->getNamedItem($attribute)->value != $expectedvalue) {
+                if ($node->getAttribute($attribute) != $expectedvalue) {
                     $result = false;
                 }
             }
Index: lib/weblib.php
=========================================================
--- lib/weblib.php	(revision 1.1305)
+++ lib/weblib.php	Sat Jul 25 15:29:32 WST 2009
@@ -318,7 +318,7 @@
      *
      * The added params override existing ones if they have the same name.
      *
-     * @param array $params Defaults to null. If null then return value of param 'name'.
+     * @param array $params Defaults to null. If null then returns all params.
      * @return array Array of Params for url.
      */
     public function params($params = null) {
@@ -484,6 +484,41 @@
 }
 
 /**
+ * Given an unknown $url type (string or moodle_url), returns a string URL.
+ * A relative URL is handled with $PAGE->url but gives a debugging error.
+ *
+ * @param mixed $url The URL (moodle_url or string)
+ * @param bool $stripformparams Whether or not to strip the query params from the URL
+ * @return string
+ */
+function prepare_url($url, $stripformparams=false) {
+    global $CFG, $PAGE;
+
+    $output = $url;
+
+    if ($url instanceof moodle_url) {
+        $output = $url->out($stripformparams);
+    }
+
+    // Handle relative URLs
+    if (substr($output, 0, 4) != 'http' && substr($output, 0, 1) != '/') {
+        if (preg_match('/(.*)\/([A-Za-z0-9-_]*\.php)$/', $PAGE->url->out(true), $matches)) {
+            debugging('Relative URLs are deprecated, please use an absolute URL in your code', DEBUG_DEVELOPER);
+            return $matches[1] . "/$output";
+        } else {
+            throw new coding_exception('Your page uses bizarre relative URLs which Moodle cannot handle. Please use absolute URLs.');
+        }
+    }
+
+    // Add wwwroot only if the URL does not already start with http:// or https://
+    if (!preg_match('|https?://|', $output) ) {
+        $output = $CFG->wwwroot . $output;
+    }
+
+    return $output;
+}
+
+/**
  * Determine if there is data waiting to be processed from a form
  *
  * Used on most forms in Moodle to check for data
@@ -552,157 +587,6 @@
     return $output;
 }
 
-/**
- * This function will print a button/link/etc. form element
- * that will work on both Javascript and non-javascript browsers.
- *
- * Relies on the Javascript function openpopup in javascript.php
- * All parameters default to null, only $type and $url are mandatory.
- *
- * $url must be relative to home page  eg /mod/survey/stuff.php
- *
- * @global object
- * @param string $type Can be 'button' or 'link'
- * @param string $url Web link. Either relative to $CFG->wwwroot, or a full URL.
- * @param string $name Name to be assigned to the popup window (this is used by
- *   client-side scripts to "talk" to the popup window)
- * @param string $linkname Text to be displayed as web link
- * @param int $height Height to assign to popup window
- * @param int $width Height to assign to popup window
- * @param string $title Text to be displayed as popup page title
- * @param string $options List of additional options for popup window
- * @param bool $return If true, return as a string, otherwise print
- * @param string $id id added to the element
- * @param string $class class added to the element
- * @return string
- */
-function element_to_popup_window ($type=null, $url=null, $name=null, $linkname=null,
-                                  $height=400, $width=500, $title=null,
-                                  $options=null, $return=false, $id=null, $class=null) {
-
-    if (is_null($url)) {
-        debugging('You must give the url to display in the popup. URL is missing - can\'t create popup window.', DEBUG_DEVELOPER);
-    }
-
-    global $CFG;
-
-    if ($options == 'none') { // 'none' is legacy, should be removed in v2.0
-        $options = null;
-    }
-
-    // add some sane default options for popup windows
-    if (!$options) {
-        $options = 'menubar=0,location=0,scrollbars,resizable';
-    }
-    if ($width) {
-        $options .= ',width='. $width;
-    }
-    if ($height) {
-        $options .= ',height='. $height;
-    }
-    if ($id) {
-        $id = ' id="'.$id.'" ';
-    }
-    if ($class) {
-        $class = ' class="'.$class.'" ';
-    }
-    if ($name) {
-        $_name = $name;
-        if (($name = preg_replace("/\s/", '_', $name)) != $_name) {
-            debugging('The $name of a popup window shouldn\'t contain spaces - string modified. '. $_name .' changed to '. $name, DEBUG_DEVELOPER);
-        }
-    } else {
-        $name = 'popup';
-    }
-
-    // get some default string, using the localized version of legacy defaults
-    if (is_null($linkname) || $linkname === '') {
-        $linkname = get_string('clickhere');
-    }
-    if (!$title) {
-        $title = get_string('popupwindowname');
-    }
-
-    $fullscreen = 0; // must be passed to openpopup
-    $element = '';
-
-    switch ($type) {
-        case 'button':
-            $element = '<input type="button" name="'. $name .'" title="'. $title .'" value="'. $linkname .'" '. $id . $class .
-                       "onclick=\"return openpopup('$url', '$name', '$options', $fullscreen);\" />\n";
-            break;
-        case 'link':
-            // Add wwwroot only if the URL does not already start with http:// or https://
-            if (!preg_match('|https?://|', $url)) {
-                $url = $CFG->wwwroot . $url;
-            }
-            $element = '<a title="'. s(strip_tags($title)) .'" href="'. $url .'" '.
-                       "onclick=\"this.target='$name'; return openpopup('$url', '$name', '$options', $fullscreen);\">$linkname</a>";
-            break;
-        default :
-            print_error('cannotcreatepopupwin');
-            break;
-    }
-
-    if ($return) {
-        return $element;
-    } else {
-        echo $element;
-    }
-}
-
-/**
- * Creates and displays (or returns) a link to a popup window, using element_to_popup_window function.
- *
- * Simply calls {@link element_to_popup_window()} with type set to 'link'
- * @see element_to_popup_window()
- *
- * @param string $url Web link. Either relative to $CFG->wwwroot, or a full URL.
- * @param string $name Name to be assigned to the popup window (this is used by
- *   client-side scripts to "talk" to the popup window)
- * @param string $linkname Text to be displayed as web link
- * @param int $height Height to assign to popup window
- * @param int $width Height to assign to popup window
- * @param string $title Text to be displayed as popup page title
- * @param string $options List of additional options for popup window
- * @param bool $return If true, return as a string, otherwise print
- * @param string $id id added to the element
- * @param string $class class added to the element
- * @return string html code to display a link to a popup window.
- */
-function link_to_popup_window ($url, $name=null, $linkname=null,
-                               $height=400, $width=500, $title=null,
-                               $options=null, $return=false) {
-
-    return element_to_popup_window('link', $url, $name, $linkname, $height, $width, $title, $options, $return, null, null);
-}
-
-/**
- * Creates and displays (or returns) a buttons to a popup window, using element_to_popup_window function.
- *
- * Simply calls {@link element_to_popup_window()} with type set to 'button'
- * @see element_to_popup_window()
- *
- * @param string $url Web link. Either relative to $CFG->wwwroot, or a full URL.
- * @param string $name Name to be assigned to the popup window (this is used by
- *   client-side scripts to "talk" to the popup window)
- * @param string $linkname Text to be displayed as web link
- * @param int $height Height to assign to popup window
- * @param int $width Height to assign to popup window
- * @param string $title Text to be displayed as popup page title
- * @param string $options List of additional options for popup window
- * @param bool $return If true, return as a string, otherwise print
- * @param string $id id added to the element
- * @param string $class class added to the element
- * @return string html code to display a link to a popup window.
- */
-function button_to_popup_window ($url, $name=null, $linkname=null,
-                                 $height=400, $width=500, $title=null, $options=null, $return=false,
-                                 $id=null, $class=null) {
-
-    return element_to_popup_window('button', $url, $name, $linkname, $height, $width, $title, $options, $return, $id, $class);
-}
-
 
 /**
  * Prints a simple button to close a window
@@ -3165,240 +3049,6 @@
 
 
 /**
- * Print a self contained form with a single submit button.
- *
- * @param string $link used as the action attribute on the form, so the URL that will be hit if the button is clicked.
- * @param array $options these become hidden form fields, so these options get passed to the script at $link.
- * @param string $label the caption that appears on the button.
- * @param string $method HTTP method used on the request of the button is clicked. 'get' or 'post'.
- * @param string $notusedanymore no longer used.
- * @param boolean $return if false, output the form directly, otherwise return the HTML as a string.
- * @param string $tooltip a tooltip to add to the button as a title attribute.
- * @param boolean $disabled if true, the button will be disabled.
- * @param string $jsconfirmmessage if not empty then display a confirm dialogue with this string as the question.
- * @param string $formid The id attribute to use for the form
- * @return string|void Depending on the $return paramter.
- */
-function print_single_button($link, $options, $label='OK', $method='get', $notusedanymore='',
-        $return=false, $tooltip='', $disabled = false, $jsconfirmmessage='', $formid = '') {
-    $output = '';
-    if ($formid) {
-        $formid = ' id="' . s($formid) . '"';
-    }
-    $link = str_replace('"', '&quot;', $link); //basic XSS protection
-    $output .= '<div class="singlebutton">';
-    // taking target out, will need to add later target="'.$target.'"
-    $output .= '<form action="'. $link .'" method="'. $method .'"' . $formid . '>';
-    $output .= '<div>';
-    if ($options) {
-        foreach ($options as $name => $value) {
-            $output .= '<input type="hidden" name="'. $name .'" value="'. s($value) .'" />';
-        }
-    }
-    if ($tooltip) {
-        $tooltip = 'title="' . s($tooltip) . '"';
-    } else {
-        $tooltip = '';
-    }
-    if ($disabled) {
-        $disabled = 'disabled="disabled"';
-    } else {
-        $disabled = '';
-    }
-    if ($jsconfirmmessage){
-        $jsconfirmmessage = addslashes_js($jsconfirmmessage);
-        $jsconfirmmessage = 'onclick="return confirm(\''. $jsconfirmmessage .'\');" ';
-    }
-    $output .= '<input type="submit" value="'. s($label) ."\" $tooltip $disabled $jsconfirmmessage/></div></form></div>";
-
-    if ($return) {
-        return $output;
-    } else {
-        echo $output;
-    }
-}
-
-
-/**
- * Print a spacer image with the option of including a line break.
- *
- * @global object
- * @param int $height The height in pixels to make the spacer
- * @param int $width The width in pixels to make the spacer
- * @param boolean $br If set to true a BR is written after the spacer
- */
-function print_spacer($height=1, $width=1, $br=true, $return=false) {
-    global $CFG;
-    $output = '';
-
-    $output .= '<img class="spacer" height="'. $height .'" width="'. $width .'" src="'. $CFG->wwwroot .'/pix/spacer.gif" alt="" />';
-    if ($br) {
-        $output .= '<br />'."\n";
-    }
-
-    if ($return) {
-        return $output;
-    } else {
-        echo $output;
-    }
-}
-
-/**
- * Given the path to a picture file in a course, or a URL,
- * this function includes the picture in the page.
- *
- * @global object
- * @param string $path The path the to the picture
- * @param int $courseid The courseid the picture is associated with if any
- * @param int $height The height of the picture in pixels if known
- * @param int $width The width of the picture in pixels if known
- * @param string $link If set the image is wrapped with this link
- * @param bool $return If true the HTML is returned rather than being echo'd
- * @return string|void Depending on $return
- */
-function print_file_picture($path, $courseid=0, $height='', $width='', $link='', $return=false) {
-    global $CFG;
-    $output = '';
-
-    if ($height) {
-        $height = 'height="'. $height .'"';
-    }
-    if ($width) {
-        $width = 'width="'. $width .'"';
-    }
-    if ($link) {
-        $output .= '<a href="'. $link .'">';
-    }
-    if (substr(strtolower($path), 0, 7) == 'http://') {
-        $output .= '<img style="height:'.$height.'px;width:'.$width.'px;" src="'. $path .'" />';
-
-    } else if ($courseid) {
-        $output .= '<img style="height:'.$height.'px;width:'.$width.'px;" src="';
-        require_once($CFG->libdir.'/filelib.php');
-        $output .= get_file_url("$courseid/$path");
-        $output .= '" />';
-    } else {
-        $output .= 'Error: must pass URL or course';
-    }
-    if ($link) {
-        $output .= '</a>';
-    }
-
-    if ($return) {
-        return $output;
-    } else {
-        echo $output;
-    }
-}
-
-/**
- * Print the specified user's avatar.
- *
- * @global object
- * @global object
- * @param mixed $user Should be a $user object with at least fields id, picture, imagealt, firstname, lastname
- *      If any of these are missing, or if a userid is passed, the the database is queried. Avoid this
- *      if at all possible, particularly for reports. It is very bad for performance.
- * @param int $courseid The course id. Used when constructing the link to the user's profile.
- * @param boolean $picture The picture to print. By default (or if NULL is passed) $user->picture is used.
- * @param int $size Size in pixels. Special values are (true/1 = 100px) and (false/0 = 35px) for backward compatability
- * @param boolean $return If false print picture to current page, otherwise return the output as string
- * @param boolean $link enclose printed image in a link the user's profile (default true).
- * @param string $target link target attribute. Makes the profile open in a popup window.
- * @param boolean $alttext add non-blank alt-text to the image. (Default true, set to false for purely
- *      decorative images, or where the username will be printed anyway.)
- * @return string|void String or nothing, depending on $return.
- */
-function print_user_picture($user, $courseid, $picture=NULL, $size=0, $return=false, $link=true, $target='', $alttext=true) {
-    global $CFG, $DB, $OUTPUT;
-
-    $needrec = false;
-    // only touch the DB if we are missing data...
-    if (is_object($user)) {
-        // Note - both picture and imagealt _can_ be empty
-        // what we are trying to see here is if they have been fetched
-        // from the DB. We should use isset() _except_ that some installs
-        // have those fields as nullable, and isset() will return false
-        // on null. The only safe thing is to ask array_key_exists()
-        // which works on objects. property_exists() isn't quite
-        // what we want here...
-        if (! (array_key_exists('picture', $user)
-               && ($alttext && array_key_exists('imagealt', $user)
-                   || (isset($user->firstname) && isset($user->lastname)))) ) {
-            $needrec = true;
-            $user = $user->id;
-        }
-    } else {
-        if ($alttext) {
-            // we need firstname, lastname, imagealt, can't escape...
-            $needrec = true;
-        } else {
-            $userobj = new StdClass; // fake it to save DB traffic
-            $userobj->id = $user;
-            $userobj->picture = $picture;
-            $user = clone($userobj);
-            unset($userobj);
-        }
-    }
-    if ($needrec) {
-        $user = $DB->get_record('user', array('id'=>$user), 'id,firstname,lastname,imagealt');
-    }
-
-    if ($link) {
-        $url = '/user/view.php?id='. $user->id .'&amp;course='. $courseid ;
-        if ($target) {
-            $target='onclick="return openpopup(\''.$url.'\');"';
-        }
-        $output = '<a '.$target.' href="'. $CFG->wwwroot . $url .'">';
-    } else {
-        $output = '';
-    }
-    if (empty($size)) {
-        $file = 'f2';
-        $size = 35;
-    } else if ($size === true or $size == 1) {
-        $file = 'f1';
-        $size = 100;
-    } else if ($size >= 50) {
-        $file = 'f1';
-    } else {
-        $file = 'f2';
-    }
-    $class = "userpicture";
-
-    if (is_null($picture)) {
-        $picture = $user->picture;
-    }
-
-    if ($picture) {  // Print custom user picture
-        require_once($CFG->libdir.'/filelib.php');
-        $src = get_file_url($user->id.'/'.$file.'.jpg', null, 'user');
-    } else {         // Print default user pictures (use theme version if available)
-        $class .= " defaultuserpic";
-        $src =  $OUTPUT->old_icon_url('u/' . $file);
-    }
-    $imagealt = '';
-    if ($alttext) {
-        if (!empty($user->imagealt)) {
-            $imagealt = $user->imagealt;
-        } else {
-            $imagealt = get_string('pictureof','',fullname($user));
-        }
-    }
-
-    $output .= "<img class=\"$class\" src=\"$src\" height=\"$size\" width=\"$size\" alt=\"".s($imagealt).'"  />';
-    if ($link) {
-        $output .= '</a>';
-    }
-
-    if ($return) {
-        return $output;
-    } else {
-        echo $output;
-    }
-}
-
-/**
  * Prints a summary of a user in a nice little box.
  *
  * @global object
@@ -3599,43 +3249,6 @@
     }
 }
 
-/**
- * Print a png image.
- *
- * @global object
- * @staticvar bool $recentIE
- * @param string $url The URL of the image to display
- * @param int $sizex The width of the image in pixels
- * @param int $sizey The height of the image in pixels
- * @param boolean $return If true the HTML is returned rather than echo'd
- * @param string $parameters Additional HTML attributes to set
- * @return string|bool Depending on $return
- */
-function print_png($url, $sizex, $sizey, $return, $parameters='alt=""') {
-    global $OUTPUT;
-    static $recentIE;
-
-    if (!isset($recentIE)) {
-        $recentIE = check_browser_version('MSIE', '5.0');
-    }
-
-    if ($recentIE) {  // work around the HORRIBLE bug IE has with alpha transparencies
-        $output .= '<img src="'. $OUTPUT->old_icon_url('spacer') . '" width="'. $sizex .'" height="'. $sizey .'"'.
-                   ' class="png" style="width: '. $sizex .'px; height: '. $sizey .'px; '.
-                   ' filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='.
-                   "'$url', sizingMethod='scale') ".
-                   ' '. $parameters .' />';
-    } else {
-        $output .= '<img src="'. $url .'" style="width: '. $sizex .'px; height: '. $sizey .'px; '. $parameters .' />';
-    }
-
-    if ($return) {
-        return $output;
-    } else {
-        echo $output;
-    }
-}
-
 
 /**
  * Display a recent activity note
@@ -3677,69 +3290,6 @@
 
 
 /**
- * Prints a basic textarea field.
- *
- * When using this function, you should
- *
- * @global object
- * @param bool $usehtmleditor Enables the use of the htmleditor for this field.
- * @param int $rows Number of rows to display  (minimum of 10 when $height is non-null)
- * @param int $cols Number of columns to display (minimum of 65 when $width is non-null)
- * @param null $width (Deprecated) Width of the element; if a value is passed, the minimum value for $cols will be 65. Value is otherwise ignored.
- * @param null $height (Deprecated) Height of the element; if a value is passe, the minimum value for $rows will be 10. Value is otherwise ignored.
- * @param string $name Name to use for the textarea element.
- * @param string $value Initial content to display in the textarea.
- * @param int $obsolete deprecated
- * @param bool $return If false, will output string. If true, will return string value.
- * @param string $id CSS ID to add to the textarea element.
- * @return string|void depending on the value of $return
- */
-function print_textarea($usehtmleditor, $rows, $cols, $width, $height, $name, $value='', $obsolete=0, $return=false, $id='') {
-    /// $width and height are legacy fields and no longer used as pixels like they used to be.
-    /// However, you can set them to zero to override the mincols and minrows values below.
-
-    global $CFG;
-
-    $mincols = 65;
-    $minrows = 10;
-    $str = '';
-
-    if ($id === '') {
-        $id = 'edit-'.$name;
-    }
-
-    if ($usehtmleditor) {
-        if ($height && ($rows < $minrows)) {
-            $rows = $minrows;
-        }
-        if ($width && ($cols < $mincols)) {
-            $cols = $mincols;
-        }
-    }
-
-    if ($usehtmleditor) {
-        editors_head_setup();
-        $editor = get_preferred_texteditor(FORMAT_HTML);
-        $editor->use_editor($id, array('legacy'=>true));
-    } else {
-        $editorclass = '';
-    }
-
-    $str .= "\n".'<textarea class="form-textarea" id="'. $id .'" name="'. $name .'" rows="'. $rows .'" cols="'. $cols .'">'."\n";
-    if ($usehtmleditor) {
-        $str .= htmlspecialchars($value); // needed for editing of cleaned text!
-    } else {
-        $str .= s($value);
-    }
-    $str .= '</textarea>'."\n";
-
-    if ($return) {
-        return $str;
-    }
-    echo $str;
-}
-
-/**
  * Returns a turn edit on/off button for course in a self contained form.
  * Used to be an icon, but it's now a simple form button
  *
@@ -4313,6 +3863,7 @@
  * Showing all possible numerical grades and scales
  *
  * @todo Finish documenting this function
+ * @todo Deprecate: this is only used in a few contrib modules
  *
  * @global object
  * @param int $courseid The course ID
@@ -4354,35 +3905,6 @@
 }
 
 /**
- * Prints a scale menu (as part of an existing form) including help button
- * Just like {@link print_grade_menu()} but without the numeric grades
- *
- * @global object
- * @param int $courseid ?
- * @param string $name ?
- * @param string $current ?
- * @param boolean $return If set to true returns rather than echo's
- * @return string|bool Depending on value of $return
- */
-function print_scale_menu($courseid, $name, $current, $return=false) {
-
-    global $CFG, $OUTPUT;
-
-    $output = '';
-    $strscales = get_string('scales');
-    $output .= choose_from_menu(get_scales_menu($courseid), $name, $current, '', '', 0, true);
-
-    $linkobject = '<span class="helplink"><img class="iconhelp" alt="'.$strscales.'" src="'.$OUTPUT->old_icon_url('help') . '" /></span>';
-    $output .= link_to_popup_window ('/course/scales.php?id='. $courseid .'&amp;list=true', 'ratingscales',
-                                     $linkobject, 400, 500, $strscales, 'none', true);
-    if ($return) {
-        return $output;
-    } else {
-        echo $output;
-    }
-}
-
-/**
  * Prints a help button about a scale
  *
  * @global object
@@ -4493,95 +4015,6 @@
 /**
  * Print a help button.
  *
- * @global object
- * @global object
- * @uses DEBUG_DEVELOPER
- * @param string $page  The keyword that defines a help page
- * @param string $title The title of links, rollover tips, alt tags etc
- *           'Help with' (or the language equivalent) will be prefixed and '...' will be stripped.
- * @param string $module Which module is the page defined in
- * @param mixed $image Use a help image for the link?  (true/false/"both")
- * @param boolean $linktext If true, display the title next to the help icon.
- * @param string $text If defined then this text is used in the page, and
- *           the $page variable is ignored.
- * @param boolean $return If true then the output is returned as a string, if false it is printed to the current page.
- * @param string $imagetext The full text for the helpbutton icon. If empty use default help.gif
- * @return string|void Depending on value of $return
- */
-function helpbutton($page, $title, $module='moodle', $image=true, $linktext=false, $text='', $return=false,
-                     $imagetext='') {
-    global $CFG, $COURSE, $OUTPUT;
-
-    //warning if ever $text parameter is used
-    //$text option won't work properly because the text needs to be always cleaned and,
-    // when cleaned... html tags always break, so it's unusable.
-    if ( isset($text) && $text!='') {
-        debugging('Warning: it\'s not recommended to use $text parameter in helpbutton ($page=' . $page . ', $module=' . $module . ') function', DEBUG_DEVELOPER);
-    }
-
-    // Catch references to the old text.html and emoticons.html help files that
-    // were renamed in MDL-13233.
-    if (in_array($page, array('text', 'emoticons', 'richtext'))) {
-        $oldname = $page;
-        $page .= '2';
-        debugging("You are referring to the old help file '$oldname'. " .
-                "This was renamed to '$page' becuase of MDL-13233. " .
-                "Please update your code.", DEBUG_DEVELOPER);
-    }
-
-    if ($module == '') {
-        $module = 'moodle';
-    }
-
-    if ($title == '' && $linktext == '') {
-        debugging('Error in call to helpbutton function: at least one of $title and $linktext is required');
-    }
-
-    // Warn users about new window for Accessibility
-    $tooltip = get_string('helpprefix2', '', trim($title, ". \t")) .' ('.get_string('newwindow').')';
-
-    $linkobject = '';
-
-    if ($image) {
-        if ($linktext) {
-            // MDL-7469 If text link is displayed with help icon, change to alt to "help with this".
-            $linkobject .= $title.'&nbsp;';
-            $tooltip = get_string('helpwiththis');
-        }
-        if ($imagetext) {
-            $linkobject .= $imagetext;
-        } else {
-            $linkobject .= '<img class="iconhelp" alt="'.s(strip_tags($tooltip)).'" src="'.
-                $OUTPUT->old_icon_url('help') . '" />';
-        }
-    } else {
-        $linkobject .= $tooltip;
-    }
-
-    // fix for MDL-7734
-    if ($text) {
-        $url = '/help.php?text='. s(urlencode($text));
-    } else {
-        $url = '/help.php?module='. $module .'&amp;file='. $page .'.html';
-        // fix for MDL-7734
-        if (!empty($COURSE->lang)) {
-            $url .= '&amp;forcelang=' . $COURSE->lang;
-        }
-    }
-
-    $link = '<span class="helplink">' . link_to_popup_window($url, 'popup',
-            $linkobject, 400, 500, $tooltip, 'none', true) . '</span>';
-
-    if ($return) {
-        return $link;
-    } else {
-        echo $link;
-    }
-}
-
-/**
- * Print a help button.
- *
  * Prints a special help button that is a link to the "live" emoticon popup
  *
  * @todo Finish documenting this function
@@ -4665,36 +4098,6 @@
 }
 
 /**
- * Print a message along with "Yes" and "No" links for the user to continue.
- *
- * @global object
- * @param string $message The text to display
- * @param string $linkyes The link to take the user to if they choose "Yes"
- * @param string $linkno The link to take the user to if they choose "No"
- * @param string $optionyes The yes option to show on the notice
- * @param string $optionsno The no option to show
- * @param string $methodyes Form action method to use if yes [post, get]
- * @param string $methodno Form action method to use if no [post, get]
- * @return void Output is echo'd
- */
-function notice_yesno ($message, $linkyes, $linkno, $optionsyes=NULL, $optionsno=NULL, $methodyes='post', $methodno='post') {
-
-    global $CFG;
-
-    $message = clean_text($message);
-    $linkyes = clean_text($linkyes);
-    $linkno = clean_text($linkno);
-
-    print_box_start('generalbox', 'notice');
-    echo '<p>'. $message .'</p>';
-    echo '<div class="buttons">';
-    print_single_button($linkyes, $optionsyes, get_string('yes'), $methodyes, $CFG->framename);
-    print_single_button($linkno,  $optionsno,  get_string('no'),  $methodno,  $CFG->framename);
-    echo '</div>';
-    print_box_end();
-}
-
-/**
  * Redirects the user to another page, after printing a notice
  *
  * This function calls the OUTPUT redirect method, echo's the output
@@ -4857,93 +4260,6 @@
 }
 
 /**
- * Prints a single paging bar to provide access to other pages  (usually in a search)
- *
- * @param int $totalcount Thetotal number of entries available to be paged through
- * @param int $page The page you are currently viewing
- * @param int $perpage The number of entries that should be shown per page
- * @param mixed $baseurl If this  is a string then it is the url which will be appended with $pagevar, an equals sign and the page number.
- *                          If this is a moodle_url object then the pagevar param will be replaced by the page no, for each page.
- * @param string $pagevar This is the variable name that you use for the page number in your code (ie. 'tablepage', 'blogpage', etc)
- * @param bool $nocurr do not display the current page as a link
- * @param bool $return whether to return an output string or echo now
- * @return bool|string depending on $result
- */
-function print_paging_bar($totalcount, $page, $perpage, $baseurl, $pagevar='page',$nocurr=false, $return=false) {
-    $maxdisplay = 18;
-    $output = '';
-
-    if ($totalcount > $perpage) {
-        $output .= '<div class="paging">';
-        $output .= get_string('page') .':';
-        if ($page > 0) {
-            $pagenum = $page - 1;
-            if (!is_a($baseurl, 'moodle_url')){
-                $output .= '&nbsp;(<a class="previous" href="'. $baseurl . $pagevar .'='. $pagenum .'">'. get_string('previous') .'</a>)&nbsp;';
-            } else {
-                $output .= '&nbsp;(<a class="previous" href="'. $baseurl->out(false, array($pagevar => $pagenum)).'">'. get_string('previous') .'</a>)&nbsp;';
-            }
-        }
-        if ($perpage > 0) {
-            $lastpage = ceil($totalcount / $perpage);
-        } else {
-            $lastpage = 1;
-        }
-        if ($page > 15) {
-            $startpage = $page - 10;
-            if (!is_a($baseurl, 'moodle_url')){
-                $output .= '&nbsp;<a href="'. $baseurl . $pagevar .'=0">1</a>&nbsp;...';
-            } else {
-                $output .= '&nbsp;<a href="'. $baseurl->out(false, array($pagevar => 0)).'">1</a>&nbsp;...';
-            }
-        } else {
-            $startpage = 0;
-        }
-        $currpage = $startpage;
-        $displaycount = $displaypage = 0;
-        while ($displaycount < $maxdisplay and $currpage < $lastpage) {
-            $displaypage = $currpage+1;
-            if ($page == $currpage && empty($nocurr)) {
-                $output .= '&nbsp;&nbsp;'. $displaypage;
-            } else {
-                if (!is_a($baseurl, 'moodle_url')){
-                    $output .= '&nbsp;&nbsp;<a href="'. $baseurl . $pagevar .'='. $currpage .'">'. $displaypage .'</a>';
-                } else {
-                    $output .= '&nbsp;&nbsp;<a href="'. $baseurl->out(false, array($pagevar => $currpage)).'">'. $displaypage .'</a>';
-                }
-
-            }
-            $displaycount++;
-            $currpage++;
-        }
-        if ($currpage < $lastpage) {
-            $lastpageactual = $lastpage - 1;
-            if (!is_a($baseurl, 'moodle_url')){
-                $output .= '&nbsp;...<a href="'. $baseurl . $pagevar .'='. $lastpageactual .'">'. $lastpage .'</a>&nbsp;';
-            } else {
-                $output .= '&nbsp;...<a href="'. $baseurl->out(false, array($pagevar => $lastpageactual)).'">'. $lastpage .'</a>&nbsp;';
-            }
-        }
-        $pagenum = $page + 1;
-        if ($pagenum != $displaypage) {
-            if (!is_a($baseurl, 'moodle_url')){
-                $output .= '&nbsp;&nbsp;(<a class="next" href="'. $baseurl . $pagevar .'='. $pagenum .'">'. get_string('next') .'</a>)';
-            } else {
-                $output .= '&nbsp;&nbsp;(<a class="next" href="'. $baseurl->out(false, array($pagevar => $pagenum)) .'">'. get_string('next') .'</a>)';
-            }
-        }
-        $output .= '</div>';
-    }
-
-    if ($return) {
-        return $output;
-    }
-
-    echo $output;
-    return true;
-}
-
-/**
  * This function is used to rebuild the <nolink> tag because some formats (PLAIN and WIKI)
  * will transform it to html entities
  *
@@ -5186,42 +4502,6 @@
     return $CFG->docroot . '/' . str_replace('_utf8', '', current_language()) . '/' . $path;
 }
 
-/**
- * Returns a string containing a link to the user documentation.
- * Also contains an icon by default. Shown to teachers and admin only.
- *
- * @global object
- * @param string $path The page link after doc root and language, no leading slash.
- * @param string $text The text to be displayed for the link
- * @param string $iconpath The path to the icon to be displayed
- * @return string Either the link or an empty string
- */
-function doc_link($path='', $text='', $iconpath='') {
-    global $CFG;
-
-    if (empty($CFG->docroot)) {
-        return '';
-    }
-
-    $url = get_docs_url($path);
-
-    $target = '';
-    if (!empty($CFG->doctonewwindow)) {
-        $target = " onclick=\"window.open('$url'); return false;\"";
-    }
-
-    $str = "<a href=\"$url\"$target>";
-
-    if (empty($iconpath)) {
-        $iconpath = $CFG->httpswwwroot . '/pix/docs.gif';
-    }
-
-    // alt left blank intentionally to prevent repetition in screenreaders
-    $str .= '<img class="iconhelp" src="' .$iconpath. '" alt="" />' .$text. '</a>';
-
-    return $str;
-}
-
 
 /**
  * Standard Debugging Function
@@ -5326,58 +4606,6 @@
 
 
 /**
- * Returns an image of an up or down arrow, used for column sorting. To avoid unnecessary DB accesses, please
- * provide this function with the language strings for sortasc and sortdesc.
- *
- * If no sort string is associated with the direction, an arrow with no alt text will be printed/returned.
- *
- * @global object
- * @param string $direction 'up' or 'down'
- * @param string $strsort The language string used for the alt attribute of this image
- * @param bool $return Whether to print directly or return the html string
- * @return string|void depending on $return
- *
- */
-function print_arrow($direction='up', $strsort=null, $return=false) {
-    global $OUTPUT;
-
-    if (!in_array($direction, array('up', 'down', 'right', 'left', 'move'))) {
-        return null;
-    }
-
-    $return = null;
-
-    switch ($direction) {
-        case 'up':
-            $sortdir = 'asc';
-            break;
-        case 'down':
-            $sortdir = 'desc';
-            break;
-        case 'move':
-            $sortdir = 'asc';
-            break;
-        default:
-            $sortdir = null;
-            break;
-    }
-
-    // Prepare language string
-    $strsort = '';
-    if (empty($strsort) && !empty($sortdir)) {
-        $strsort  = get_string('sort' . $sortdir, 'grades');
-    }
-
-    $return = ' <img src="'.$OUTPUT->old_icon_url('t/' . $direction) . '" alt="'.$strsort.'" /> ';
-
-    if ($return) {
-        return $return;
-    } else {
-        echo $return;
-    }
-}
-
-/**
  * @return boolean true if the current language is right-to-left (Hebrew, Arabic etc)
  */
 function right_to_left() {
Index: theme/standard/styles_ie6.css
=========================================================
--- theme/standard/styles_ie6.css	(revision 1.24)
+++ theme/standard/styles_ie6.css	Thu Jul 23 13:52:24 WST 2009
@@ -94,3 +94,6 @@
 #mod-quiz-edit .reorder .questioncontentcontainer .randomquestioncategory label{
     width: 35%;
 }
+#help_icon_tooltip .yui-tt-shadow-visible {
+  background-color: transparent;
+}
Index: theme/standard/styles_layout.css
=========================================================
--- theme/standard/styles_layout.css	(revision 1.702)
+++ theme/standard/styles_layout.css	Fri Jul 24 11:24:16 WST 2009
@@ -595,6 +595,22 @@
     margin:0.2em 0pt;
     text-align:left;
 }
+#help_icon_tooltip {
+  font-size: 0.7em;
+}
+#help_icon_tooltip h1 {
+  font-size: 1.1em;
+  font-weight: bold;
+}
+#help_icon_tooltip div.bd {
+  width: 300px;
+}
+
+#help_icon_tooltip .readmore {
+  display: block;
+  font-style: italic;
+  margin-top:10px;
+}
 
 /***
  *** Forms
